Add float to Java Calendar - java

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.

Related

Incrementing a single parameter in an array of objects

I am trying to get the hour component of an object, which is an int, and increment it by 1. So 5 would be 6. I tried to do clocks[i].getHour() = clocks[i].getHour()+1, but this was not allowed and would say I need a variable on the left.
public void daylightSavingsTime(Clock[] clocks) {
for(int i = 0; i <clocks.length; i++) {
int a = clocks[i].getHour()+1;
}
Probably you'd need to write/use a setter function setHour(int newHour) ,
and then you could do something along the lines of:
public void daylightSavingsTime(Clock[] clocks) {
for(int i = 0; i <clocks.length; i++) {
clocks[i].setHour(clocks[i].getHour()+1);
}
Explanation of your statement.
clocks[i].getHour() = clocks[i].getHour()+1;
//To simplify
Clock clock = clocks[i];
clock.getHour() = clock.getHour()+1; //thing you are trying to do.
Suppose clock hours field is 6. What the compiler will do. When it sees clock.getHours() it knows the value is 6. To compiler your statement looks like
6 = 6+1
Obviously no language wants to change the value of 6 to 7
But int a = clocks[i].getHour()+1; is a valid statement as a will be assigned to 7.
To increment the hour in clock just use just do
clock.hours = clocks[i].getHour()+1;
but now hours property is public and can be easily abused like clock.hours = 100; but we may not want it to be 100, but to increase the date as 100 > 24. So use set method like clock.setHour(a+1) this method will internally handle the hour like
Class Clock{
// like that.. it may be different..
void setHour(int hour){
this.day += hour/24;
this.hour += hour%24;
}
}

Code crashing after using formatting

I'm new to the Java language (Just started about 2 weeks ago)
Basically, the user enters their year/month/day they were born on in order and I use this information to perform a math calculation that will show their age.
I need numbers from 0-9 to be taken in as 01, 02, 03... So, I searched around and found that I can use Decimal.Format and then print out the format later on.
My code crashes whenever it reaches the println(twodigits.format) part no mater where I put it. There are no errors displayed that I need to address.
Why is it doing this and is there a better way to do this? I need it to be 2 digits at all times or the calculation won't work.
Here's a part of my code, I can provide more if needed.
DecimalFormat twodigits = new DecimalFormat("00");
System.out.println("Calculating...");
Integer CurrentDate2 = Integer.valueOf(CurrentDate);
Integer BirthDate2 = Integer.valueOf(BirthDate);
int a = CurrentDate2.intValue();
int b = BirthDate2.intValue();
int age = (a - b) / 1000;
Thread.sleep(300);
System.out.println(".");
Thread.sleep(300);
System.out.println(".");
Thread.sleep(300);
System.out.println(".");
System.out.println(twodigits.format(CurrentDate));
System.out.println(twodigits.format(BirthDate));
Any help is appreciated!
What types are "CurrentDate" and "BirthDate" because it's not clear from your code? You first use them to set "CurrentDate2" and "BirthDate2". And then you use them in the println().
If I were to guess, I'd say they are of type 'String', and 'twodigits.format()' can't handle Strings, which is why it's crashing.
This takes two dates and split time on "/". It then prints them out in the format that you want.
DecimalFormat twodigits = new DecimalFormat("00");
System.out.println("Calculating...");
String CurrentDate = "01/02/2007";
String BirthDate = "02/03/2007";
String[] currentDateParts = CurrentDate.split("/");
String[] birthDateParts = BirthDate.split("/");
int cdp0 = Integer.parseInt(currentDateParts[0]);
int cdp1 = Integer.parseInt(currentDateParts[1]);
int cdp2 = Integer.parseInt(currentDateParts[2]);
int bdp0 = Integer.parseInt(birthDateParts[0]);
int bdp1 = Integer.parseInt(birthDateParts[1]);
int bdp2 = Integer.parseInt(birthDateParts[2]);
//do your calculations
System.out.println(twodigits.format(cdp0));
System.out.println(twodigits.format(cdp1));
System.out.println(twodigits.format(cdp2));
System.out.println(twodigits.format(bdp0));
System.out.println(twodigits.format(bdp1));
System.out.println(twodigits.format(bdp2));

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 i could make a jess rule in java

I am a begginer at jess rules so i can't understand how i could use it. I had read a lot of tutorials but i am confused.
So i have this code :
Date choosendate = "2013-05-05";
Date date1 = "2013-05-10";
Date date2 = "2013-05-25";
Date date3 = "2013-05-05";
int var = 0;
if (choosendate.compareTo(date1)==0)
{
var = 1;
}
else if (choosendate.compareTo(date2)==0)
{
var = 2;
}
else if (choosendate.compareTo(date3)==0)
{
var = 3;
}
How i could do it with jess rules?
I would like to make a jess rules who takes the dates , compare them and give me back in java the variable var. Could you make me a simple example to understand it?
This problem isn't a good fit for Jess as written (the Java code is short and efficient as-is) but I can show you a solution that could be adapted to other more complex situations. First, you would need to define a template to hold Date, int pairs:
(deftemplate pair (slot date) (slot score))
Then you could create some facts using the template. These are somewhat equivalent to your date1, date2, etc, except they associate each date with the corresponding var value:
(import java.util.Date)
(assert (pair (date (new Date 113 4 10)) (score 1)))
(assert (pair (date (new Date 113 4 25)) (score 2)))
(assert (pair (date (new Date 113 4 5)) (score 3)))
We can define a global variable to hold the final, computed score (makes it easier to get from Java.) This is the equivalent of your var variable:
(defglobal ?*var* = 0)
Assuming that the "chosen date" is going to be in an ordered fact chosendate, we could write a rule like the following. It replaces your chain of if statements, and will compare your chosen date to all the dates in working memory until it finds a match, then stop:
(defrule score-date
(chosendate ?d)
(pair (date ?d) (score ?s))
=>
(bind ?*var* ?s)
(halt))
OK, now, all the code above goes in a file called dates.clp. The following Java code will make use of it (the call to Rete.watchAll() is included so you can see some interesting trace output; you'd leave that out in a real program):
import jess.*;
// ...
// Get Jess ready
Rete engine = new Rete();
engine.batch("dates.clp");
engine.watchAll();
// Plug in the "chosen date"
Date chosenDate = new Date(113, 4, 5);
Fact fact = new Fact("chosendate", engine);
fact.setSlotValue("__data", new Value(new ValueVector().add(chosenDate), RU.LIST));
engine.assertFact(fact);
// Run the rule and report the result
int count = engine.run();
if (count > 0) {
int score = engine.getGlobalContext().getVariable("*var*").intValue(null);
System.out.println("Score = " + score);
} else {
System.out.println("No matching date found.");
}
As I said, this isn't a great fit, because the resulting code is larger and more complex than your original. Where using a rule engine makes sense is if you've got multiple rules that interact; such a Jess program has no more overhead than this, and so fairly quickly starts to look like a simplification compared to equivalent Java code. Good luck with Jess!

Java convert float to integer

I want to do an operation like this : if the given float numbers are like 1.0 , 2.0 , 3.0 , I want to save them to database as integer (1,2,3 ), if they are like 1.1 , 2.1 , ,3.44 , I save them as float. what's the best solution for this problem using java ? The corresponding field in database is type of varchar.
Just try int i = (int) f;.
EDIT : I see the point in the question. This code might work :
int i = (int) f;
String valToStore = (i == f) ? String.valueOf(i) : String.valueOf(f);
String result = "0";
if (floatVar == Math.floor(floatVar)) {
result = Integer.toString((int) floatVar);
} else {
result = Float.toString(floatVar);
}
The if-clause checks whether the number is a whole number - i.e. if it is equal to the result of rounding it down to the closest whole value.
But this is very odd requirement indeed, and perhaps you should reconsider the need for such a thing.
Seems like you want to save Floats with no trailing numbers as Integers, while saving those with significant trailing numbers as Floats. I would rather just save it all as Float to the DB, but it's your question so here's my answer:
/**
* Method to determine if trailing numbers are significant or not. Significant
* here means larger than 0
*
* #param fFloat
* #return
*/
public static boolean isTrailingSignificant(Float fFloat)
{
int iConvertedFloat = fFloat.intValue();// this drops trailing numbers
// checks if difference is 0
return ((fFloat - iConvertedFloat) > 0);
}
This is how you would use this method:
Number oNumToSave = null;
if (isTrailingSignificant(fFloat))
{
// save float value as is
oNumToSave = fFloat;
}
else
{
// save as int
oNumToSave = fFloat.intValue();// drops trailing numbers
}
After that, you can do the database operation using the variable oNumToSave.
Not sure this is the best solution, but you can try to write a method like this :
String convertToString(Float f) {
if (f.toString().endsWith(".0"))
return f.intValue().toString();
else
return f.toString();
}
Kotlin:
val mAmount = 3.0
val intAmount = mAmount.toInt()
val amountToDisplay = if (intAmount.compareTo(mAmount) == 0) intAmount.toString() else java.lang.String.valueOf(mAmount)

Categories