I'm new to Java and my problem here is a Simple Age Calculator. Here is my Code:
public class Client {
public int findAge(String birthDate) throws InvalidDateFormatException {
// InvalidDateFormatException is a custom defined
int age = 0;
try {
Calendar past = new GregorianCalendar();
Calendar present = Calendar.getInstance();
past.setTime(new SimpleDateFormat("dd-MM-yyyy", Locale.ENGLISH).parse(birthDate));
age = present.get(Calendar.YEAR) - past.get(Calendar.YEAR);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return (age >= 0) ? age : 0;
}
In main,
try {
System.out.println(c.findAge("08-09-1015"));
} catch (InvalidDateFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Now, this is throwing a ParseException every time i pass a String in the wrong Format. Is there any way in which I can make it throw an InvalidDateFormatException Exception instead?
Also, please leave a comment on the style and quality of my Code, provided I'm following the correct coding standards and adhering to best practices.
To answer your prime question, you need to throw the custom exception in the catch block:
try {
Calendar past = new GregorianCalendar();
Calendar present = Calendar.getInstance();
past.setTime(new SimpleDateFormat("dd-MM-yyyy", Locale.ENGLISH).parse(birthDate));
age = present.get(Calendar.YEAR) - past.get(Calendar.YEAR);
} catch (ParseException e) {
throw new InvalidDateFormatException("invalid date: " + birthDate);
}
Regarding your code, I have a couple of suggestions:
Do not use new GregorianCalendar() and prefer Calendar.getInstance().
The way you calculate the age is broken: you don't take into account the month and the day (let's say we are 2015-09-20, and the birth date is 2014-12-01, your code will output 1 even if the baby is not 1 year old yet).
Consider giving a Date argument instead of a String argument. It should not be the responsibility of the findAge method to parse the birth date.
If you are using Java 8, consider using the new Java Time API.
Define Custom Exception class for InvalidDateFormatException as below:
public class InvalidDateFormatException extends RuntimeException {
private String errorMessage;
public InvalidDateFormatException(String errorMessage, Exception exe) {
super(errorMessage);
exe.printStackTrace();
}
}
Modify your catch block to throw the exception as below :
public class Client {
public int findAge(String birthDate) throws InvalidDateFormatException {
int age = 0;
try {
Calendar past = new GregorianCalendar();
Calendar present = Calendar.getInstance();
past.setTime(new SimpleDateFormat("dd-MM-yyyy", Locale.ENGLISH).parse(birthDate));
age = present.get(Calendar.YEAR) - past.get(Calendar.YEAR);
} catch (ParseException e) {
throw new InvalidDateFormatException("Invalid Date Format while finding Age", e);
}
return (age >= 0) ? age : 0;
}
}
Also, I would suggest you go through the below site:
https://docs.oracle.com/javase/tutorial/essential/exceptions/creating.html
Related
I am trying to change the account expiration date in windows active directory.
I can able to change the Never option in account expiry using the below code .
final Modification mod = new Modification(ModificationType.REPLACE,
"accountExpires", "9223372036854775807");//Can change the required date with milliseconds
LDAPResult result=connection.modify(userDN, mod);
But , If I tried to change the account expiry date means , the code executed successfully and success was printed in console . But the date is not changed in the AD.
Here is my code to change or extend the account expiry date.
public class AccountExpireSetting {
public void ChangeAccountExpires(String userDN,String password , String dateToChange) throws LDAPException
{
LDAPConnection connection=null;
String someDate = null;
try {
connection = new LDAPConnectionObject().getConnection();
} catch (LDAPException e1) {
e1.printStackTrace();
}
try{
SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy");
Date date = sdf.parse(dateToChange);
System.out.println("Date to MillSeconds : "+date.getTime());
someDate = String.valueOf(date.getTime());
Date date1=new Date(date.getTime());
System.out.println("MillSeconds to Date : "+date1);
}
catch(Exception e){
e.printStackTrace();
}
try{
System.out.println("Going to replace account expires to never");
final Modification mod = new Modification(ModificationType.REPLACE,
"accountExpires", someDate);// 9223372036854775807 milliseconds can change the password to never expire
// 9223372036854775807
LDAPResult result=connection.modify(userDN, mod);
System.out.println("Account expires status : " + result); // Password status : LDAPResult(resultCode=0 (success), messageID=2, opType='modify')
}catch(LDAPException e) {
// TODO Auto-generated catch block
System.out.println("Error in replacing account expires to never");
e.printStackTrace();
}finally
{
System.out.println("Closing the connection.");
connection.close();
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
String temp="CN=Anand,OU=Java,OU=Chennai,OU=Department,dc=tstdmn,dc=com";
try {
new AccountExpireSetting().ChangeAccountExpires(temp, "password#123","08.06.2014");
} catch (LDAPException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Hope you people will give a better solution.
The acountExpires is not milliseconds but rather the number of 100 nanosecond intervals since January 1, 1601 (UTC).
If a user object in Active Directory has never had an expiration date, the accountExpires attribute is set to a huge number. The actual value is 2^63 – 1, or 9,223,372,036,854,775,807. This is because 64-bit numbers can range from -2^63 to 2^63 - 1, making this the largest number that can be saved as a 64-bit value. Obviously this represents a date so far in the future that it cannot be interpreted. In fact, AccountExpirationDate raises an error if it attempts to read this value. If a user object has an expiration date, and then you remove this date in ADUC by selecting "Never" on the "Account" tab, the GUI sets accountExpires to 0. Thus, the values 0 and 2^63 - 1 both really mean "Never"
For one way to change in Java try looking at this discussion.
-jim
I'm new to Android programming and taking a Coursera class. In my assignment app, I'm trying to catch any exceptions when the user does not enter or enters incorrect time information (HH:MM:SS).
My app crashes right after user error instead of displaying my Toast message or displaying a Log message to Logcat.
SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
try {
Date dt = formatter.parse(MileTime);
Calendar cal = Calendar.getInstance();
cal.setTime(dt);
int hours = cal.get(Calendar.HOUR);
int minutes = cal.get(Calendar.MINUTE);
int seconds = cal.get(Calendar.SECOND);
int duration = 3600 * hours + 60 * minutes + seconds;
int steps_per_second = 3;
int running_rate = duration * steps_per_second;
//pleaseStop = false; //DouglasZare example, don't need this.
mHandler = new Handler(); // .os package class when importing
mLeftfoot = findViewById(R.id.leftfoot);
mRightfoot = findViewById(R.id.rightfoot);
mFootAnim = AnimationUtils.loadAnimation(this, R.anim.foot); //this looks to the foot.xml file for the animations
stepRecursive();
} catch (ParseException e) {
e.printStackTrace();
Log.e(TAG, "Invalid Mile Time Entry", e);
Toast.makeText(Assignment3MainActivity_V3_DouglasZare_AnimationCancel.this,
"Please Enter Valid Time Stamp HH:MM:SS", Toast.LENGTH_LONG).show();
}
The error log is here: http://pastebin.com/By7FWxLk.
This error makes perfect sense and is intentional.
Caused by: java.text.ParseException: Unparseable date: ""
What do I fix to get my catch statement to prevent this?
Fixed. Ugh. I changed ParseException to just Exception. It doesn't make any sense to me...The Exception I want to catch IS ParseException.
catch (Exception e) {
e.printStackTrace();
Log.e(TAG, "Invalid Mile Time Entry", e);
Toast.makeText(Assignment3MainActivity_V3_DouglasZare_AnimationCancel.this,
"Please Enter Valid Time Stamp HH:MM:SS", Toast.LENGTH_LONG).show();
}
The reason is the exception being thrown is IllegalStateException not ParseException.
If you look at line 5 of your crash log, you'll see the exception that gets passed up to you is an IllegalStateException. This is because the ParseException is caught and then an IllegalStateException is re-thrown afterwards.
Here's an example of multiple catch blocks.
try {
//some code that can throw an exception
} catch (IllegalStateException e) {
//catch the IllegalStateExeption
} catch (Exception e) {
//catch all the ones I didn't think of.
}
I am trying to develop user login/signup using JSP in MVC. The program will be doing a simple login, create and update for the user. In the model part I am supposed to return 0, 1, 2, 3 based on the following criteria.
0 if the user is validated successfully
1 if the user is validated successfully but has a weak password
2 if the user is validated successfully but has an expired password (over 1 year old)
3 if the user is not validated
Here is the code for the validate method which I have done till now,
public int Validate() {
try {
Class.forName(driverName).newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
Connection connection = DriverManager.getConnection(dbURL,
username, password);
String verifyQuery = "SELECT COUNT(email), dateSet, strength FROM users WHERE email=? AND hashPassword=SHA2(CONCAT(?, salt), 256)";
PreparedStatement verify = connection.prepareStatement(verifyQuery);
verify.setString(1, email);
verify.setString(2, pass);
ResultSet verified = verify.executeQuery();
while (verified.next()) {
if (verified.getInt(1) == 1) {
email_db = verified.getString(2);
pass_db = verified.getString(3);
date = verified.getDate(5);
strength = verified.getString(6);
}
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (email_db.equals(email) && pass_db.equals(pass)) {
status = 0;
}
if (email_db.equals(email) && pass_db.equals(pass)
&& strength.equals("weak")) {
status = 1;
}
if (email_db.equals(email) && pass_db.equals(pass) && date> ){
}
return status;
}
I am confused about the Date part, any suggestions? Should I write a new method for the Date part?
Using plain Java, you can achieve this using the java.util.Calendar and java.util.Date classes. Here's a code sample for a function that checks if it has passed a year using the current datetime
public boolean hasPassedAYear(Date date) {
long currentDate = Calendar.getInstance().getTimeInMillis();
long dateToEval = date.getTime();
// 1000 => milliseconds to seconds
// 60 => seconds to minutes
// 60 => minutes to hours
// 24 => hours to days
long days = (currentDate - dateToEval) / (1000 * 60 * 60 * 24);
return days >= 365;
}
Still, if you want a good code (like everyone), you should use Joda Time that provides a better Date/Time handling. This would be the same function but using Joda time library:
public boolean hasPassedAYear(Date date) {
DateTime currentDate = new DateTime();
DateTime dateToEval = new DateTime(date);
Interval interval = new Interval(dateToEval, currentDate);
return interval.toPeriod().getYears() >= 1;
}
It's up to you which method to choose. IMHO, I would use the code with Joda Time for the ease of readability, understanding and maintenance.
I assume the date that you get from the database is the date when the password was created/last modified . In that case will a compare to today's date to get the number of days not work ?
Check this post and answers for sample code .
Try below code
java.util.Date lastDate = result.getTimestamp("date");
java.util.Date todaysDate = new java.util.Date(System.currentTimeMillis());
long days1 = lastDate.getTime()/(60*60*24*1000);
long days2 = todaysDate.getTime()/(60*60*24*1000);
long difference = days2-days1;
You can use use this code..
if (email_db.equals(email) && pass_db.equals(pass) ){
Date dt = date;//Your Date from database
Calendar passCreatedOn = Calendar.getInstance();
passCreatedOn.setTime(dt);
Calendar today=Calendar.getInstance();
Integer noOfDays=( (today.getTime() - passCreatedOn.getTime()) / (1000 * 60 * 60 * 24));
if(noOfDays>365)
{
return 2
}
}
I want to show to a colleague that SimpleDateFormat is not thread-safe through a simple JUnit test. The following class fails to make my point (reusing SimpleDateFormat in a multi-threaded environment) and I don't understand why. Can you spot what is preventing my use of SDF from throwing a runtime exception?
public class SimpleDateFormatThreadTest
{
#Test
public void test_SimpleDateFormat_MultiThreaded() throws ParseException{
Date aDate = (new SimpleDateFormat("dd/MM/yyyy").parse("31/12/1999"));
DataFormatter callable = new DataFormatter(aDate);
ExecutorService executor = Executors.newFixedThreadPool(1000);
Collection<DataFormatter> callables = Collections.nCopies(1000, callable);
try{
List<Future<String>> futures = executor.invokeAll(callables);
for (Future f : futures){
try{
assertEquals("31/12/1999", (String) f.get());
}
catch (ExecutionException e){
e.printStackTrace();
}
}
}
catch (InterruptedException e){
e.printStackTrace();
}
}
}
class DataFormatter implements Callable<String>{
static SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
Date date;
DataFormatter(Date date){
this.date = date;
}
#Override
public String call() throws RuntimeException{
try{
return sdf.format(date);
}
catch (RuntimeException e){
e.printStackTrace();
return "EXCEPTION";
}
}
}
Lack of thread safety doesn't necessarily mean that the code will throw an exception. This was explained in Andy Grove's article, SimpleDateFormat and Thread Safety, which is no longer available online. In it, he showed SimpleDateFormat's lack of thread safety by showing that the output would not always be correct, given different inputs.
When I run this code, I get the following output:
java.lang.RuntimeException: date conversion failed after 3 iterations.
Expected 14-Feb-2001 but got 01-Dec-2007
Note that "01-Dec-2007" isn't even one of the strings in the test data. It is actually a combination of the dates being processed by the other two threads!
While the original article is no longer available online, the following code illustrates the issue. It was created based on articles that appeared to have been based on Andy Grove's initial article.
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
public class SimpleDateFormatThreadSafety {
private final SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MMM-yyyy", Locale.US);
public static void main(String[] args) {
new SimpleDateFormatThreadSafety().dateTest(List.of("01-Jan-1999", "14-Feb-2001", "31-Dec-2007"));
}
public void dateTest(List<String> testData) {
testData.stream()
.map(d -> new Thread(() -> repeatedlyParseAndFormat(d)))
.forEach(Thread::start);
}
private void repeatedlyParseAndFormat(String value) {
for (int i = 0; i < 1000; i++) {
Date d = tryParse(value);
String formatted = dateFormat.format(d);
if (!value.equals(formatted)) {
throw new RuntimeException("date conversion failed after " + i
+ " iterations. Expected " + value + " but got " + formatted);
}
}
}
private Date tryParse(String value) {
try {
return dateFormat.parse(value);
} catch (ParseException e) {
throw new RuntimeException("parse failed");
}
}
}
Sometimes this conversion fails by returning the wrong date, and sometimes it fails with a NumberFormatException:
java.lang.NumberFormatException: For input string: ".E2.31E2"
Isn't this part from javadoc of SimpleDateFormatter has sufficent proof about it?
Synchronization
Date formats are not synchronized. It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally.
And the major observation of not being thread safe is to get unexpected results and not an exception.
It is not thread safe because of this code in SimpleDateFormat (in sun JVM 1.7.0_02):
private StringBuffer format(Date date, StringBuffer toAppendTo,
FieldDelegate delegate) {
// Convert input date to time field list
calendar.setTime(date);
....
}
Each call to format stores the date in a calendar member variable of the SimpleDateFormat, and then subsequently applies the formatting to the contents of the calendar variable (not the date parameter).
So, as each call to format happens the data for all currently running formats may change (depending on the coherence model of your architecture) the data in the calendar member variable that is used by every other thread.
So if you run multiple concurrent calls to format you may not get an exception, but each call may return a result derived from the date of one of the other calls to format - or a hybrid combination of data from many different calls to format.
Just working on my java assignment and I've hit a brick wall I just cant seem to find a solution for - I'm not necessarily looking for an answer, even some ideas to what tools might help me :) Anyway here goes:
As the title says, I am looking to create a calendar object within an object within an Arraylist. Basically, as per the code below - I thought that when an instance of the Appointment object was created the link between the calendar object and the appointment object would be severed and I could reuse the Calendar object for the next appointment object. Unfortunately each object retains its reference to the calendar object, rather than create its own instance of the Calendar object =/.
Some background on the work:
Basically this piece of java code, scans the file and extracts the information out of it, makes sure its valid then creates an instance of the appropriate object within the one of the two arraylists. I'm working within constraints of my tutor who has specified that I must use an arraylist. Any help would greatly appreciated.
The constructor for the appointment class:
public Appointment (Patient patient, Provider provider, GregorianCalendar date, boolean standard, boolean attended)
Example Appointment Data
Appointment#84736254193#123456AF#22.30#20/12/2012#false#True
public AppointmentsManager (String path) {
this.path = path;
String[] fileLine;
boolean throwError = false;
DateFormat df = new SimpleDateFormat ("HH.mm dd/MM/yyyy");
df.setLenient(false);
GregorianCalendar calendar = new GregorianCalendar();
try {
Scanner input = new Scanner(new File(path));
String line;
while (input.hasNext()) {
line = input.nextLine();
fileLine = line.split("#");
if (fileLine.length < 0)
throw new IllegalArgumentException("Error: the data in the file is has not been delimited correctly. Please review");
if (fileLine[0].matches("Provider")) {
if (fileLine.length < 7)
throw new IllegalArgumentException("Error: the provider data in the file is incomplete. Please review");
persons.add(new Provider(fileLine[1], fileLine[2], fileLine[3], fileLine[4], fileLine[5],
fileLine[6]));
}
else if (fileLine[0].matches("Patient")) {
fileLine = line.split("#");
if (fileLine.length < 11)
throw new IllegalArgumentException("Error: the patient data in the file is incomplete. Please review");
for (int i = 0; i < persons.size(); i++) {
if (persons.get(i).getMedicare().matches(fileLine[10])) {
persons.add(new Patient(fileLine[1], fileLine[2], fileLine[3], fileLine[4], fileLine[5],
fileLine[6], fileLine[7], fileLine[8], Integer.parseInt(fileLine[9]),(Provider)persons.get(i)));
throwError = true;
}
}
if (throwError!=true) {
throw new IllegalArgumentException("Error: the provided Provider does not exist for Patient: " + fileLine[2]+", "+fileLine[1] +". Please review");
}
}
else if (fileLine[0].matches("Appointment")) {
fileLine = line.split("#");
if (fileLine.length < 7)
throw new IllegalArgumentException("Error: the appointment data in the file is incomplete. Please review");
if (!"true".equals(fileLine[5].toLowerCase()) && !"false".equals(fileLine[5].toLowerCase()))
throw new IllegalArgumentException("Error: the appointment data in the file is incorrect. Please review");
if (!"true".equals(fileLine[6].toLowerCase()) && !"false".equals(fileLine[6].toLowerCase()))
throw new IllegalArgumentException("Error: the appointment data in the file is incorrect. Please review");
//parse the fileLine parameters
calendar.setTime(df.parse(fileLine[3] + " " + fileLine[4]));
for (int i = 0; i < persons.size(); i++) {
if (persons.get(i).getMedicare().matches(fileLine[1])) {
for (int j = 0; j < persons.size(); j++) {
if (persons.get(j).getMedicare().matches(fileLine[2])) {
appointments.add(new Appointment((Patient) persons.get(i), (Provider) persons.get(j), calendar,
Boolean.parseBoolean(fileLine[5]), Boolean.parseBoolean(fileLine[6])));
throwError = true;
}
}
}
}
if (throwError!=true) {
throw new IllegalArgumentException("Error: the provided Provider or Patient does not exist in the system. Please review");
}
}
else
throw new IllegalArgumentException("Error: the data provided does not match a person, provider or appointment. Please review");
}
input.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParseException pe) {
// TODO Auto-generated catch block
throw new IllegalArgumentException("Error: the appointment date and time in the file is incorrect. Please review");
}
}
well you are sending same object to each appointment. If I understand it correctly, you want each appointment to have different calendar object. If so, just reinstantiate the calendar every time appointment is created, either in the appointment constructor or your method...
edit:
oh, I forgot, Calendar is singleton. Then I would suggest to keep only java.util.Date object in an Appointment - Calendar.getTime() creates new instance of Date.
Then you can dress it as Calendar in the getter -
public Calendar getAppointmentCalendar()
{
Calendar cal = Calendar.getInstance();
cal.setTime(this.appDate);
return cal;
}
The issue is that same calendar instance is getting passed to constructor each time. Instantiate a new Calendar instance inside the for loop where you are adding the appointment to the list. Passing a new instance would solve your issue.