I am trying to generate an EPOCH value. I am using the following:
int currentEpoch = ((int) System.currentTimeMillis()) / 1000;
Log.v("EPOCH", String.valueOf(currentEpoch));
Below is my log:
Why is my Epoch value negative?
System.currentTimeMillis() returns a long value. When you cast it to int the value is overflowing and giving you a negative number.
Try
long currentEpoch = System.currentTimeMillis() / 1000;
Log.v("EPOCH", String.valueOf(currentEpoch));`
In short, there's a reason that System.currentTimeMillis() returns a long. An int isn't large enough to store the number of milliseconds since 1970. Because it's trying to represent a value larger than it can hold, the value wraps around and becomes a negative value.
Related
I am trying to divide two time durations (java.time.Duration) and to perform that there are two methods
java.time.Duration#dividedBy(long) which returns an object of type Duration itself but due to some API restrictions I can not use this version.
java.time.Duraiton#dividedBy(Duration) which returns a long and returns number of times one duration occurs within other duration but here we lose the precision as it does not care about the remainder.
Is there any way out to perform this division and get the result with remainder.
Duration.ofHours(1).dividedBy(7L); //returns 8M34.28571 seconds
Duration.ofHours(1).dividedBy(Duration.ofSeconds(7L)) // returns 514 seconds
I have a restriction not to use the first way. Can I get the results using some other way?
EDIT: (from comments) I am not allowed to convert a Duration instance to an ordinal value, e.g. milliseconds.
Convert to milliseconds/nanoseconds, then divide their ordinal value(s), then create a new Duration object from the result.
When the easy ways are forbidden, you can of course do it the more cumbersome way. The following is similar to how we learned to do division by hand in school.
Duration dividend = Duration.ofHours(1);
long divisor = 7;
long minutes = dividend.toMinutes() / divisor;
dividend = dividend.minusMinutes(minutes * divisor);
long seconds = dividend.toSeconds() / divisor;
dividend = dividend.minusSeconds(seconds * divisor);
long nanoseconds = dividend.toNanos() / divisor;
Duration result = Duration.ofMinutes(minutes)
.plusSeconds(seconds)
.plusNanos(nanoseconds);
System.out.println(result);
Result output:
PT8M34.285714285S
Your requirements are not that precise, so I can’t be sure I haven’t used a forbidden method, though.
In the Microsoft Spec, DATETIME is represented as 2 32-bit integers: low and high
Reference: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/cca27429-5689-4a16-b2b4-9325d93e4ba2
The FILETIME structure is a 64-bit value that represents the number of
100-nanosecond intervals that have elapsed since January 1, 1601,
Coordinated Universal Time (UTC). typedef struct _FILETIME { DWORD
dwLowDateTime; DWORD dwHighDateTime; } FILETIME,
*PFILETIME,
*LPFILETIME; dwLowDateTime: A 32-bit unsigned integer that contains the low-order bits of the file time. dwHighDateTime: A 32-bit unsigned
integer that contains the high-order bits of the file time.
For example, here is the long 130280867040000000
So the the high and low computed with
int high = (int)(fullval >> 32);
int low = (int)fullval;
so high = 30333378
and low = 552794112
How do I compute these to a Java 8 Instant?
Ah I was barking up the wrong tree when I split the bytes in half like that.
Basically it's just saying that the units are in 100ns.
And the Epoch has a different base time too. So you have to add the offset as well.
So it is:
private static final long DATETIME_EPOCH_DIFF_1601;
static {
LocalDateTime time32Epoch1601 = LocalDateTime.of(1601, Month.JANUARY, 1, 0, 0);
Instant instant = time32Epoch1601.atZone(ZoneOffset.UTC).toInstant();
DATETIME_EPOCH_DIFF_1601 = (instant.toEpochMilli() - Instant.EPOCH.toEpochMilli()) / 1000;
}
Instant answer = Instant.ofEpochSecond(fullval / 10000000 + DATETIME_EPOCH_DIFF_1601)
For converting with 1 second precision your own answer is just fine. In case you also need to convert the fraction of second, here’s one way to do that.
Instant msFiletimeEpoch = Instant.parse("1601-01-01T00:00:00Z");
// a tick is 100 nanoseconds
int nanosPerTick = 100;
long ticksPerSecond = TimeUnit.SECONDS.toNanos(1) / nanosPerTick;
long fullval = 130_280_867_040_000_000L;
long seconds = fullval / ticksPerSecond;
long nanos = fullval % ticksPerSecond * nanosPerTick;
Instant answer = msFiletimeEpoch.plusSeconds(seconds).plusNanos(nanos);
System.out.println(answer);
Output is:
2013-11-05T00:58:24Z
Let’s try to put 1 more tick on your oroginal value; it should add 100 nanoseconds.
long fullval = 130_280_867_040_000_001L;
2013-11-05T00:58:24.000000100Z
So so it does.
Caveat for very far future dates: According to your quote the Microsoft integers are both unsigned. A Java long is signed. So some time in year 30828 we will start getting results that are very wrong. Just in case we ought to throw an exception if the long value is negative.
I just stepped onto problem with generating id for notification in Android.
I'm going through some notification-handling-sdk and they are using this code to generate notification id:
private int generateTimestampId() {
return (int)(new Date().getTime() % 2147483647L);
}
This is probably good solution, but I can't understand what % 2147483647L stands for in context of epoch time.
(please note: new Date().getTime() returns the number of milliseconds since January 1, 1970, 00:00:00 GMT)
It could be done to prevent negative values which will happen when long is narrowed to int. Consider the following code:
long value = 1L + Integer.MAX_VALUE; // anything past max integer
int i1 = (int) value; // -2147483648
int i2 = (int) (value % 2147483647L); // 1
With the % 2147483647L the code ensures that the number will always be smaller than Integer.MAX_VALUE, which is 2147483647, before it will get narrowed to int.
It more or less makes sense in context of generated ids, we rarely use negative numbers for this use case.
I'm trying to type out a code that outputs random words from a list, the user must type back as many words as possible before 60 seconds has elapsed I am using currentTimeMillis() to keep track of time so this is difficult for me to figure out I tried the code below and it said 6000000000000 is too large of a number but when I output the current/start time, it output 1512409897444 so this doesn't make sense to me.
long currentTime = System.currentTimeMillis();
long startTime = System.currentTimeMillis();
System.out.println(currentTime);
System.out.println(startTime);
while (startTime <= 6000000000000)
{
(etc. ect.)
}
What you want to do is compare the current time against the time you started and check if their difference is below 60 seconds, aka 60000 milli seconds:
long startTime = System.currentTimeMillis();
while ((System.currentTimeMillis() - startTime) <= 60000) {
// still under 60 seconds...
}
System.currentTimeMillis() returns a value that increases from an "epoch". You must subtract two time values to determine the amount of time that has elapsed.
long startTime = System.currentTimeMillis();
long elapsedTime = 0;
while (elapsedTime <= 60000) {
// etc, etc, etc
elapsedTime = System.currentTimeMillis() - startTime;
}
As others have already answered you have to subtract the starting time to the current time to determine if the difference is greather than 60 seconds (60,000 milliseconds). Also you can use TimeUnit to get a more readeable code:
long startTime = System.currentTimeMillis();
while (TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - startTime) <= 60) {
//do stuff
}
EDIT
If you are wondering why 6000000000000 gives you an error and the result of currentTimeMillis() (1512409897444) doesn't, is because they are different datatypes: int (32 bits) vs long (64 bits). The literal value 6000000000000 is interpreted as an int value which is greather than the max supported 32-bit signed int value (2,147,483,647) and the compiler doesn't allow that. It would work if you use a long literal instead 6000000000000L (note the L at the end). Signed long's max supported value is 9,223,372,036,854,775,807. The result of System.currentTimeMillis() is a long value hence 1512409897444 is valid. Read Primitive Data Types for further information.
Lets say i have long currentMillis and long oldMillis. The difference between the two timestamps is very tiny and always less than 1 second.
If i want to know the difference between the timestamps in milleseconds, i can do the following:
long difference = currentmillis-oldmillis;
And if i want to convert difference to seconds, i can just divide it by 1000. However if the difference in milliseconds is less than 1000 milliseconds(<1 second), dividing it by 1000 will result in 0.
How can i get the difference between the two timestamps if the difference is less than a second? For example, if the difference is 500 milliseconds, the desired output is 0.5 seconds.
Using float/double instead of long always returns 0.0 for some reason i don't understand.
My code:
private long oldmillis = 0, difference = 0;
private long calculateDifference()
{
long currentMillis = System.currentTimeMillis();
if (oldMillis == 0) oldMillis = currentMillis;
difference = currentMillis - oldMillis;
oldMillis = currentMillis;
return difference;
}
The method calculateDifference is called randomly with a small random time interval.
It sounds like you just need to convert the results into double before the division:
// This will work
double differenceMillis = currentMillis - oldMillis;
double differenceSeconds = differenceMillis / 1000;
// This will *not* work
double differenceSecondsBroken = (currentMillis - oldMillis) / 1000;
In the latter code, the division is performed using integer arithmetic, so you'll end up with a result of 0 that is then converted to a double.
An alternative which would work is to divide by 1000.0, which would force the arithmetic to be done using floating point:
double differenceSeconds = (currentMillis - oldMillis) / 1000.0;