Java BigDecimal Rounding - java

I am learning BigDecimal and i want it to retrieve the exact number i entered, the following code is rouding the number and i dont know why
public static BigDecimal parseFromNumberString(String numberString) {
if (numberString != null) {
String nonSpacedString =
numberString.replaceAll("[ \\t\\n\\x0B\\f\\r]", "").replaceAll("%", "");
int indexOfComma = nonSpacedString.indexOf(',');
int indexOfDot = nonSpacedString.indexOf('.');
NumberFormat format = null;
if (indexOfComma < indexOfDot) {
nonSpacedString = nonSpacedString.replaceAll("[,]", "");
format = new DecimalFormat("##.#");
} else if (indexOfComma > indexOfDot) {
nonSpacedString = nonSpacedString.replaceAll("[.]", "");
DecimalFormatSymbols otherSymbols = new DecimalFormatSymbols();
otherSymbols.setDecimalSeparator(',');
format = new DecimalFormat("##,#", otherSymbols);
} else {
format = new DecimalFormat();
}
try {
return new BigDecimal(format.parse(nonSpacedString).doubleValue(), new MathContext(12));
} catch (ParseException e) {
// unrecognized number format
return null;
}
}
return null;
}
If i do something like
public static void main(String[] args){
BigDecimal d = Test.parseFromNumberString("0.39");
System.out.println(d);
}
The value printed is 0,00 and not 0.39

Try this code:
public static BigDecimal parseFromNumberString(String numberString) {
if (numberString != null) {
String nonSpacedString =
numberString.replaceAll("[ \\t\\n\\x0B\\f\\r]", "").replaceAll("%", "");
int indexOfComma = nonSpacedString.indexOf(',');
int indexOfDot = nonSpacedString.indexOf('.');
DecimalFormat decimalFormat = new DecimalFormat();
DecimalFormatSymbols symbols = new DecimalFormatSymbols();
String pattern = "#0.0#";
if (indexOfComma < indexOfDot) {
symbols.setDecimalSeparator('.');
} else if (indexOfComma > indexOfDot) {
symbols.setDecimalSeparator(',');
}
try {
decimalFormat = new DecimalFormat(pattern, symbols);
decimalFormat.setParseBigDecimal(true);
BigDecimal toRet = (BigDecimal) decimalFormat.parse(nonSpacedString);
return toRet.setScale(12);
} catch (ParseException e) {
return null;
}
}
return null;
}
public static void main(String... args) {
BigDecimal d = Test.parseFromNumberString("0,39");
System.out.println(d);
}
Is that what you want??

i just ran your code and i get. 0.390000000000 maybe you forgot to save?
try cleanning your project, restart your ide and recompile. the code should work fine

Related

Android EditText currency for Malaysia

Locale currency = new Locale("ms-my");
//Locale of Malaysia
if (!editable.toString().equals(current)) {
TransferAmount.removeTextChangedListener(this);
String replaceable = String.format("[%s,.\\s]", NumberFormat.getCurrencyInstance(currency)
.getCurrencyInstance().getCurrency().getSymbol());
String cleanString = editable.toString().replaceAll(replaceable, "");
double parsed;
try {
parsed = Double.parseDouble(cleanString);
} catch (NumberFormatException e) {
parsed = 0.00;
}
NumberFormat formatter = NumberFormat.getCurrencyInstance();
formatter.setMaximumFractionDigits(0);
String formatted = formatter.format((parsed));
current = formatted;
TransferAmount.setSelection(formatted.length());
TransferAmount.addTextChangedListener(this);
}
I would like to set the Currency as Malaysia and the Malaysia Country Code is "ms-my". I would like to add Malaysia currency symbol in front of the text. Is there anyway?
Simple solution would be add the Malaysia Country Code "ms-my" like a prefix
EditText editable = (EditText)findViewById(Your_id);
editable.addTextChangedListener(currencyFormatWatcher);
private final TextWatcher currencyFormatWatcher = new TextWatcher() {
String prefix = "ms-my "; //"MYR "
Locale currency = new Locale("ms-my");
public void afterTextChanged(Editable s) {
if(!s.toString().equals("")){
editable.removeTextChangedListener(this);
String replaceable = String.format("[%s,.\\s]", NumberFormat.getCurrencyInstance(currency)
.getCurrencyInstance().getCurrency().getSymbol());
String cleanString = editable.toString().replace(prefix, "").replaceAll(replaceable, "");
double parsed;
try {
parsed = Double.parseDouble(cleanString);
} catch (NumberFormatException e) {
parsed = 0.00;
}
NumberFormat formatter = NumberFormat.getCurrencyInstance();
formatter.setMaximumFractionDigits(0);
String formatted = formatter.format((parsed));
formatted = prefix.concat(formatted);
editable.setText(formatted);
editable.setSelection(formatted.length());
editable.addTextChangedListener(this);
}
}
};
Check this answers

Java Format Timestamp

I have below Java code to convert string format to Timestamp object
public class TestUtil{
Object result;
Public Object convertFormat(String format, String value, String type){
String format = "yyyyMMddHHmmss";
String value = "20050225144824";
SimpleDateFormat dformat = new SimpleDateFormat(format);
java.util.Date date = dformat.parse(value);
result = new Timestamp(date.getTime);
System.out.println("Result::"+ result);
}
}
Expected outcome:
I was expecting the outcome should be like below
20050225144824
Actual outcome:
2005-02-25 14:48:24.0
Could anyone tell me what I am missing here? To get "20050225144824" this result
The below code runs fine for me.
Adding few print statements to explain the different behaviors.
import java.util.Date;
import java.text.SimpleDateFormat;
import java.sql.Timestamp;
public class Main
{
public static void main(String[] args) {
String myFormat = "yyyyMMddHHmmss";
String value = "20050225144824";
try {
SimpleDateFormat dformat = new SimpleDateFormat("yyyyMMddHHmmss");
Date date = dformat.parse(value);
Timestamp ts = new Timestamp(date.getTime());
Object result = new Timestamp(date.getTime());
System.out.println("Timestamp Format with yyyyMMddHHmmss : " +dformat.format(ts));
System.out.println("Object Format with yyyyMMddHHmmss : " +result);
System.out.println("Object Format with yyyyMMddHHmmss : " +dformat.format(result));
} catch(Exception e) {
e.printStackTrace();
}
}
}
Here is the output of the different behaviors :
Timestamp Format with yyyyMMddHHmmss : 20050225144824
Object Format with yyyyMMddHHmmss : 2005-02-25 14:48:24.0
Object Format with yyyyMMddHHmmss : 20050225144824
If you expect Timestamp to return your custom output then you need to override the default Timestamp library.
Here I create CustomTimestamp.java to extend Timestamp and override its toString() method. I modified the changes according to your requirement.
public class CustomTimestamp extends Timestamp {
private int nanos;
public CustomTimestamp(long time) {
super(time);
}
#Override
public String toString () {
int year = super.getYear() + 1900;
int month = super.getMonth() + 1;
int day = super.getDate();
int hour = super.getHours();
int minute = super.getMinutes();
int second = super.getSeconds();
String yearString;
String monthString;
String dayString;
String hourString;
String minuteString;
String secondString;
String nanosString;
String zeros = "000000000";
String yearZeros = "0000";
StringBuffer timestampBuf;
if (year < 1000) {
// Add leading zeros
yearString = "" + year;
yearString = yearZeros.substring(0, (4-yearString.length())) +
yearString;
} else {
yearString = "" + year;
}
if (month < 10) {
monthString = "0" + month;
} else {
monthString = Integer.toString(month);
}
if (day < 10) {
dayString = "0" + day;
} else {
dayString = Integer.toString(day);
}
if (hour < 10) {
hourString = "0" + hour;
} else {
hourString = Integer.toString(hour);
}
if (minute < 10) {
minuteString = "0" + minute;
} else {
minuteString = Integer.toString(minute);
}
if (second < 10) {
secondString = "0" + second;
} else {
secondString = Integer.toString(second);
}
if (nanos == 0) {
nanosString = "";
} else {
nanosString = Integer.toString(nanos);
// Add leading zeros
nanosString = zeros.substring(0, (9-nanosString.length())) +
nanosString;
// Truncate trailing zeros
char[] nanosChar = new char[nanosString.length()];
nanosString.getChars(0, nanosString.length(), nanosChar, 0);
int truncIndex = 8;
while (nanosChar[truncIndex] == '0') {
truncIndex--;
}
nanosString = new String(nanosChar, 0, truncIndex + 1);
}
// do a string buffer here instead.
timestampBuf = new StringBuffer(20+nanosString.length());
timestampBuf.append(yearString);
timestampBuf.append(monthString);
timestampBuf.append(dayString);
timestampBuf.append(hourString);
timestampBuf.append(minuteString);
timestampBuf.append(secondString);
timestampBuf.append(nanosString);
return (timestampBuf.toString());
}
}
Your main class should use CustomTimestamp to get the output
try {
String format = "yyyyMMddHHmmss";
String value = "20050225144824";
SimpleDateFormat dformat = new SimpleDateFormat(format);
java.util.Date date;
date = dformat.parse(value);
Timestamp result = new CustomTimestamp(date.getTime());
System.out.println("Result::" + result);
} catch (ParseException e) {
e.printStackTrace();
}

Force DecimalFormat to throw ParseException if not all the string is parseable

I want to configure my DecimalFormat instance so that it fails to parse a string if not all the string is parsable.
If I run the below code, the output I get is:
I could parse the string, and the result is: 2000
However I would like it to throw an exception because it contains non-digits: MMM
public static void main(String[] args) {
try {
DecimalFormat df = new DecimalFormat();
DecimalFormatSymbols symbols = new DecimalFormatSymbols();
symbols.setDecimalSeparator(',');
symbols.setGroupingSeparator('.');
df.setDecimalFormatSymbols(symbols);
Number n = df.parse("2.000.MMM,77");
System.out.println("I could parse the string, and the result is: " + n);
} catch (ParseException pe) {
pe.printStackTrace();
}
}
You could add yourself a little utility method like this:
private static Number parse(DecimalFormat df, String input) throws ParseException {
final ParsePosition position = new ParsePosition(0);
final Number result = df.parse(input, position);
if (position.getErrorIndex() != -1) {
throw new ParseException("could not parse input='" + input + "'", position.getErrorIndex());
} else if (position.getIndex() < input.length()) {
throw new ParseException("input='" + input + "' wasnt processed completely", position.getIndex());
}
return result;
}
It will throw an exception if the input wasnt processed completely
You could also extend DecimalFormat and add the above method like so:
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.ParsePosition;
public class ThrowingDecimalFormat extends DecimalFormat {
public Number parseSafe(String input) throws ParseException {
final ParsePosition position = new ParsePosition(0);
final Number result = parse(input, position);
if (position.getErrorIndex() != -1) {
throw new ParseException("could not parse input='" + input + "'", position.getErrorIndex());
} else if (position.getIndex() < input.length()) {
throw new ParseException("input='" + input + "' wasnt processed completely", position.getIndex());
}
return result;
}
}

enforcing specific date format in java

In my java program a java variable String inputDate accepts input form user. I want to enforce users to enter date in (dd/MM/yyyy) format only as my other modules depend on that format only. Here's what I tried so far:
public class InputQuery {
private static String FLIGHT_DATE;
public String getFLIGHT_DATE() {
return FLIGHT_DATE;
}
public void setFLIGHT_DATE() {
boolean invalid = true;
Scanner sc = null;
while(invalid){
System.out.println("Enter FLIGHT_DATE(dd/MM/yyy) :");
sc = new Scanner(System.in);
FLIGHT_DATE = sc.nextLine();
if( (invalid = isValidDate(FLIGHT_DATE)) ) {
System.out.println("For Feb 21,2016 enter 21/02/2016");
}
}
sc.close();
}
private boolean isValidDate(String flight_DATE) {
SimpleDateFormat myDateFormat = new SimpleDateFormat("dd/MM/yyyy");
if( flightDate.parse(flight_DATE)){
System.out.println("accepted OK");
return true;
}
return false;
}
Use myDateFormat.setLenient(false).
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
sdf.setLenient(false);
try{
sdf.parse(incomingDateString);
// if you get here, the incomingDateString is valid
}catch(ParseException ex){
// if you get here, the incomingDateString is invalid
}
This won't work, try this
private boolean isValidDate(String flightDate) {
SimpleDateFormat myDateFormat = new SimpleDateFormat("dd/MM/yyyy");
myDateFormat.setLenient(false);
try {
myDateFormat.parse(flightDate);
} catch (ParseException e) {
return false;
}
System.out.println("accepted OK");
return true;
}
You can use regex to check given input is in format or not try this:
public class DateValidator {
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
String flightDate = null;
boolean isDateValid = false;
while(!isDateValid){
System.out.print("Enter FLIGHT_DATE(dd/MM/yyy) :");
flightDate = scanner.nextLine().trim();
isDateValid = isDateValid(flightDate);
if(!isDateValid){
System.out.println("Wrong Format.");
}
}
System.out.println("continue.");
}
public static boolean isDateValid(String flightDate){
String regex = "^\\d{2}/\\d{2}/\\d{4}$";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(flightDate);
return matcher.find();
}
}
To my understanding, what you'd like to do is to ensure that the date entered corresponds to the format.
The parse(String) method doesn't return a boolean, and it never returns null. If it's successful, it returns a date; if it's unsuccessful, it throws an exception. The way to do this is:
private boolean isValidDate(String flight_DATE) {
SimpleDateFormat myDateFormat = new SimpleDateFormat("dd/MM/yyyy");
try {
myDateFormat.parse(flight_DATE);
return true;
} catch (ParseException ex) {
// You may want to print the exception here, or do something else with it
return false;
}
}

How do I validate a timestamp?

my application takes in a string like this "2002-10-15 10:55:01.000000". I need to validate that the string is a valid for a db2 timestamp.
How can I do this?
EDIT: This mostly works
public static boolean isTimeStampValid(String inputString) {
SimpleDateFormat format = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS");
try {
format.parse(inputString);
return true;
} catch (ParseException e) {
return false;
}
}
The problem is that if I pass it a bad format for milliseconds like "2011-05-02 10:10:01.0av" this will pass validation. I am assuming that since the first millisecond character is valid then it just truncates the rest of the string.
I'm not exactly sure about the format but you you can play around it and can try something like this
public static bool isTimeStampValid(String inputString)
{
SimpleDateFormat format = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS");
try{
format.parse(inputString);
return true;
}
catch(ParseException e)
{
return false;
}
}
EDIT: if you want to validate for numbers after successful parsing, you could do
format.parse(inputString);
Pattern p = Pattern.compile("^\\d{4}[-]?\\d{1,2}[-]?\\d{1,2} \\d{1,2}:\\d{1,2}:\\d{1,2}[.]?\\d{1,6}$");
return p.matcher(inputString).matches();
instead of
format.parse(inputString);
return true;
http://download.oracle.com/javase/6/docs/api/java/text/SimpleDateFormat.html
I believe the format would be "yyyy-MM-dd HH:mm:ss.SSSSSS"
Call parse(String) and catch ParseException indicating it is invalid.
/**
* This method validates the given time stamp in String format
* #param timestamp
* #return
*/
public static boolean isTimeStampValid(String timestamp) {
//(Considering that formal will be yyyy-MM-dd HH:mm:ss.SSSSSS )
//Tokenize string and separate date and time
boolean time = false;
try {
//Tokenize string and separate date and time
StringTokenizer st = new StringTokenizer(timestamp, " ");
if (st.countTokens() != 2) {
return false;
}
String[] dateAndTime = new String[2];
int i = 0;
while (st.hasMoreTokens()) {
dateAndTime[i] = st.nextToken();
i++;
}
String timeToken = dateAndTime[1];
StringTokenizer timeTokens = new StringTokenizer(timeToken, ":");
if (timeTokens.countTokens() != 3) {
return false;
}
String[] timeAt = new String[4];
int j = 0;
while (timeTokens.hasMoreTokens()) {
timeAt[j] = timeTokens.nextToken();
j++;
}
try {
int HH = Integer.valueOf(timeAt[0].toString());
int mm = Integer.valueOf(timeAt[1].toString());
float ss = Float.valueOf(timeAt[2].toString());
if (HH < 60 && HH >= 0 && mm < 60 && mm >= 0 && ss < 60 && ss >= 0) {
time = true;
} else {
}
} catch (Exception e) {
e.printStackTrace();
}
//Got Date
String dateToken = dateAndTime[0];//st.nextToken();
//Tokenize separated date and separate year-month-day
StringTokenizer dateTokens = new StringTokenizer(dateToken, "-");
if (dateTokens.countTokens() != 3) {
return false;
}
String[] tokenAt = new String[3];
//This will give token string array with year month and day value.
int k = 0;
while (dateTokens.hasMoreTokens()) {
tokenAt[k] = dateTokens.nextToken();
k++;
}
//Now try to create new date with got value of date
int dayInt = Integer.parseInt(tokenAt[2]);
int monthInt = Integer.parseInt(tokenAt[1]);
int yearInt = Integer.parseInt(tokenAt[0]);
Calendar cal = new GregorianCalendar();
cal.setLenient(false);
cal.set(yearInt, monthInt - 1, dayInt);
cal.getTime();//If not able to create date it will throw error
} catch (Exception e) {
e.printStackTrace();
return false;
}
//Here we ll check for correct format is provided else it ll return false
try {
Pattern p = Pattern.compile("^\\d{4}[-]?\\d{1,2}[-]?\\d{1,2} \\d{1,2}:\\d{1,2}:\\d{1,2}[.]?\\d{1,6}$");
if (p.matcher(timestamp).matches()) {
} else {
return false;
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
//Cross checking with simple date format to get correct time stamp only
SimpleDateFormat format = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS");
try {
format.parse(timestamp);
//return true;
if (time) {
return true;
} else {
return false;
}
} catch (ParseException e) {
e.printStackTrace();
return false;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
If you're already connected to the database, you can execute a query that attempts to cast the input string as a timestamp, and check for a failure message (in this case, SQLSTATE 22007).
VALUES CAST( ? AS TIMESTAMP )
The above query will fully validate the input string while consuming hardly any resources on the database server. If the string is invalid for any reason, your database client will encounter an exception.

Categories