System.currentTimeMillis() to int returns negative value - java

I am developing an app in which I am adding views dynamically and assigning an unique id using but it is returning negative value:
long time = System.currentTimeMillis();
view.setId((int)time);
So I searched on google and found another solution but however it also doesn't work. It also returns negative value:
Long time = System.currentTimeMillis();
view.setId(time.intValue());
So how can I convert long value returned by System.currentTimeMills() to int safely?
System.currentTimeMills() returns 1505645107314 while converting to int returns -1888413582.

The value will be changed when a large long value is casted to int. You may want to divided the time by 1000 to get time in seconds, or subtract the value from time of 1 day ago (depending upon the uniqueness you prefer) and use it as the id of the view.
view.setId((int)(time/1000)); //this gives unique id for every second.
Edit
Use following code to get unique id for every millisecond:
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DATE, -1);
long yesterday = calendar.getTimeInMillis();
int uniqueId = (int) (yesterday - System.currentTimeMillis());

currentTimeMillis returns a long, which can sometimes not fit into an int. Therefore, I don't think you should use this as a way to set unique int ids for views.
If you want a unique int for each of the views you create, try this approach, create a static counter thingy:
static int nextViewID = 0;
When you create a new view, you just
view.setId(nextViewID);
nextViewID++;
If you want a random unique integer, you can do something like this:
Create a static Set
Generate a random integer using java.util.Random
Try to add the number to the set
Keep generating another integer until you successfully added the number to the set

This is normal. Casting from a large data type (such as long) to a smaller data type (like int), in some cases, might lead to a change in value. You can devise other means by dividing by a certain preset constant (say 10,000). For example:
Long t = System.currentTimeMillis() / 10000;
view.setId((int) t);
This would surely give you a positive value!

You can't do it. Why do you use time as unique id? Bad approach.
For instance, 2147483648 would be represented as -2147483648. For small values, casting is enough:
long l = 42;
int i = (int) l;
However, a long can hold more information than an int, so it's not possible to perfectly convert from long to int, in the general case.
You can use Hash values within integer limit as unique id.

Related

Add float to Java Calendar

I'm currently developing some functionality that needs to either subtract or add time to a Calendar class instance. The time I need to add/sub is in a properties file and could be any of these formats:
30,sec
90,sec
1.5,min
2,day
2.333,day
Let's assume addition for simplicity. I would read those values in a String array:
String[] propertyValues = "30,sec".split(",");
I would read the second value in that comma-separated pair, and map that to the relevant int in the Calendar class (so for example, "sec" becomes Calendar.SECOND, "min" becomes Calendar.MINUTE):
int calendarMajorModifier = mapToCalendarClassIntValues(propertyValues[1]);
To then do the actual operation I would do it as simple as:
cal.add(calendarMajorModifier, Integer.parseInt(propertyValues[0]));
This works and it's not overly complicated. The issue is now floating values (so 2.333,day for eaxmple) - how would you deal with it?
String[] propertyValues = "2.333,day".split(",");
As you can imagine the code becomes quite hairy (I haven't actually written it yet, so please ignore syntax mistakes)
float timeComponent = Float.parseFloat(propertyValues[0]);
if (calendarMajorModifier == Calendar.DATE) {
int dayValue = Integer.parseFloat(timeComponent);
cal.add(calendarMajorModifier, dayValue);
timeComponent = (timeComponent - dayValue) * 24; //Need to convert a fraction of a day to hours
if (timeComponent != 0) {
calendarMajorModifier = Calendar.HOUR;
}
}
if (calendarMajorModifier == Calendar.HOUR) {
int hourValue = Integer.parseFloat(timeComponent);
cal.add(calendarMajorModifier, hourValue);
timeComponent = (timeComponent - hourValue) * 60; //Need to convert a fraction of an hour to minutes
if (timeComponent != 0) {
calendarMajorModifier = Calendar.MINUTE;
}
}
... etc
Granted, I can see how there may be a refactoring opportunity, but still seems like a very brute-forceish solution.
I am using the Calendar class to do the operations on but could technically be any class. As long as I can convert between them (i.e. by getting the long value and using that), as the function needs to return a Calendar class. Ideally the class also has to be Java native to avoid third party licensing issues :).
Side note: I suggested changing the format to something like yy:MM:ww:dd:hh:mm:ss to avoid floating values but that didn't pan out. I also suggested something like 2,day,5,hour, but again, ideally needs to be format above.
I'd transform the value into the smallest unit and add that:
float timeComponent = Float.parseFloat(propertyValues[0]);
int unitFactor = mapUnitToFactor(propertyValues[1]);
cal.add(Calendar.SECOND, (int)(timeComponent * unitFactor));
and mapUnitToFactor would be something like:
int mapUnitToFactor(String unit)
{
if ("sec".equals(unit))
return 1;
if ("min".equals(unit))
return 60;
if ("hour".equals(unit))
return 3600;
if ("day".equals(unit))
return 24*3600;
throw new InvalidParameterException("Unknown unit: " + unit);
}
So for example 2.333 days would be turned into 201571 seconds.

Error with calendar class and generating numbers

I'm trying to do random number generation using the given date to create good pseudo-random numbers in Java. I decided to use the Calendar class and to count milliseconds in the day. This worked to some extent, but I can only get a different random value when I start the program. Running it any more times in the program will just give me the same number. I'm using Thread.sleep() to make sure that there is an actual difference on time, but I still get the same numbers.
Heres my method that I'm calling (from another class)
public long genRNG()
{
long mask = 0xFFFF000000000000L;
long randomValue = seed & mask;
seed = 0x5D588B656C078965L * cal.get(Calendar.MILLISECOND) + 0x0000000000269EC3;
return randomValue;
}
and here's my main method
public static void main(String[] args) throws InterruptedException
{
Seed key = new Seed();
for (int x = 0; x <=10; x++)
{
Thread.sleep(200);
System.out.println(key.genRNG());
}
}
and the given output:
-7389844038561562624
-7389844038561562624
-7389844038561562624
-7389844038561562624
-7389844038561562624
-7389844038561562624
-7389844038561562624
-7389844038561562624
-7389844038561562624
It seems you are setting mask to the same value each time and seed to the same value each time, so seed & mask yields the same value each time. A Calendar object does not automatically change its value after it has been instantiated — in other words it keeps the time it got when you constructed it (typically the time when it was constructed) until you explicitly change it. So one suggestion is to do reinitialize cal in each call to genRNG().
Here I have changed cal to a local variable:
long mask = 0xFFFF000000000000L;
long randomValue = seed & mask;
Calendar cal = Calendar.getInstance();
seed = 0x5D588B656C078965L * cal.get(Calendar.MILLISECOND) + 0x0000000000269EC3;
return randomValue;
Now I can get output like:
0
8430738502437568512
-2453898846963499008
2916080758722396160
3291568377654411264
-1326873040214032384
-951385421282017280
1212312724692795392
-3406128693175648256
-1298444067566256128
-5916885485434699776
The initial 0 comes from seed not having been initialized. I gather it’s not a problem in your code.
I don’t think you’re there yet, though. Calendar.get(Calendar.MILLISECOND) always returns a value in the interval 0 through 999, so you are getting up to 1000 different “random” values. Not a lot for storing in a long. You may get more for instance like this:
seed = 0x5D588B656C078965L * System.currentTimeMillis() + 0x0000000000269EC3;
If for some reason you want an object for the current time rather than just the long you get from System.currentTimeMillis(), if you can use Java 8, I suggest Instant.now().toEpochMilli(). It gives you the same long value, but Instant.now() gives you an object representing the current time, much like Calendar.getInstance(), only more modern and more versatile if you want to use it for other purposes.
Another issue is because of the mask your value will always end in 48 zeroes in binary representation (it’s easy to see all the values are even). Maybe this is as designed?
Also I suppose there is a reason why you are not just using java.util.Random.

How do I add an "L" to the end of an integer?

I'm trying to add a L to the end of this integer and I get an error to make it a long. I need it to be in the form of an integer though...
Can someone please help me?
Here is my code:
int timeBetween = plugin.getConfig().getInt("timeBetweenSendsInTicks");
timeBetween = timeBetween + "L";
Although, remember, it must strictly be an INTEGER!
EDIT: I need it to be something that goes with this:
scheduler.scheduleSyncRepeatingTask(this, new Runnable() {
#Override
public void run() {
#SuppressWarnings("unused")
BukkitTask task = new Timer(JavaPlugin.getPlugin(GodSends.class), amountOfChest).runTaskTimer(JavaPlugin.getPlugin(GodSends.class), 20, timeBetweenChest);
String startMSG = plugin.getConfig().getString("startMSG");
getServer().broadcastMessage(startMSG);
}
}, 0L, timeBetween); //< this needs to have an L at the end, I have it set to 60000 in the config, but I cant seem to get the L after it.
It seems the API you're using scheduler.scheduleSyncRepeatingTask() expects the last two parameters to be of type long. Since, an int can implicitly fit into a long, passing timeBetween as it is will work just fine.
Same goes for the second parameter too. You can pass 0 instead of 0L there as well. It works out the same. Basically, you're gaining nothing by explicitly passing a long literal here. They make sense in cases where you want to assign a long with a literal value that's outside of the integer's range.
You appear to be trying to make an int variable into a long variable at runtime by putting an "L" 'at the end' of the integer. This is not the correct way to do this.
Putting an L at the end of a numeric integer literal within a java program will cause the compiler to treat it as a long value instead of an int value. But you aren't feeding a literal to the compiler, so the "L" notation doesn't help you here.
I think what you need is to cast your int to a long for passing to your method, whatever it is -- so instead of
}, 0L, timeBetween);
you should have
}, 0L, (long) timeBetween);

Is there a way to prevent an int value from deleting the first 0?

As the title says , for example I have the value 02 I want the first zero to stay there so I can control my pendingIntent.
my program basically has a list , every item has it's own options , the only way I can control alertmanager is by knowing the exact unique id so I can cancel the right notification , but I couldn't come up with a solution other than this:
int FirstListPosition = getArguments().getInt(EXTRA_FirstListPosition);
int InnerListPosition = getArguments().getInt(EXTRA_PASSEDPOSITION);
String Merge = Integer.toString(FirstListPosition) + Integer.toString(InnerListPosition);
int FinalValue = Integer.parseInt(Merge);
so if I click the first item in my main list , the FirstListPosition will be 0 and if I click the third item in my list inside of the main list the InnerListPosition will be 2
so the string merge will be = 02 , this way the unique id will never be the same and I can actually get the position of the two if the user wanted to cancel a specific pendingintent " notification "
hopefully you guys understood what I meant
Have a look at NumberFormat. This class is intended to be used to format number according to a specific pattern.
If you want to encode the position in two lists into a single int value (and the number of choices in the second list is, say, less than 1000 you might use:
int encodedListPositions;
int list1Position;
int list2Position;
int encodedListPosition = list1Position*1000 + list2Position;
...
list1Position = encodedListPosition / 1000;
list2Position = endocedListPosition - 1000*list1Position;

Java: Unique 10 digit ID

I need to generate a unique 10 digit ID in Java. These are the restrictions for this ID:
Only Numeric
Maximum 10 digits
Possible to create up to 10 different IDs per second
Has to be unique (even if the application re-starts)
Not possible to save a number in the Database
As fast as possible NOT to add much lattency to the system
The best solution I found so far is the following:
private static int inc = 0;
private static long getId(){
long id = Long.parseLong(String.valueOf(System.currentTimeMillis())
.substring(1,10)
.concat(String.valueOf(inc)));
inc = (inc+1)%10;
return id;
}
This solution has the following problems:
If for any reason there is a need to create more than 10 IDs per seccond, this solution won't work.
In about 32 years this ID could be repeated (This is probably acceptable)
Any other solution to create this ID?
Any other problem I haven't thought of with mine?
Thanks for your help,
This is a small enhancement to yours but should be resilient.
Essentially, we use the current time in milliseconds unless it hasn't ticked since the last id, in which case we just return last + 1.
private static final long LIMIT = 10000000000L;
private static long last = 0;
public static long getID() {
// 10 digits.
long id = System.currentTimeMillis() % LIMIT;
if ( id <= last ) {
id = (last + 1) % LIMIT;
}
return last = id;
}
As it is it should manage up to 1000 per second with a comparatively short cycle rate. To extend the cycle rate (but shorten the resolution) you could use (System.currentTimeMillis() / 10) % 10000000000L or (System.currentTimeMillis() / 100) % 10000000000L.
This may be a crazy idea but its an idea :).
First generate UUID and get a string representation of it with
java.util.UUID.randomUUID().toString()
Second convert generated string to byte array (byte[])
Then convert it to long buffer: java.nio.ByteBuffer.wrap( byte
digest[] ).asLongBuffer().get()
Truncate to 10 digits
Not sure about uniqueness of that approach tho, I know that you can rely on uniqueness of UUIDs but haven't checked how unique are they converted and truncated to 10 digits long number.
Example was taken from JavaRanch, maybe there is more.
Edit: As you are limited to 10 digits maybe simple random generator would be enough for you, have a look into that quesion/answers on SO: Java: random long number in 0 <= x < n range
private static AtomicReference<Long> currentTime = new AtomicReference<>(System.currentTimeMillis());
public static Long nextId() {
return currentTime.accumulateAndGet(System.currentTimeMillis(), (prev, next) -> next > prev ? next : prev + 1) % 10000000000L;
}
What means that it has to be unique? Even across more currently running instances? It break your implementation.
If it must be unique across universe, the best solution is to use UUID as it's mathematically proven identifier generator as it generates unique value per universe. Less accurate number brings you collisions.
When there is only one concurrent instance, you can take current time in millis and solve 10ms problem using incrementation. If you sacrifice proper number of last positions in the number you can get many number within one milliseconds. I would than define the precision - I mean how much unique numbers do you need per seconds. You will solve the issue without any persistence using this approach.

Categories