I would like to calculate the number of the overlapping days between two date ranges. The 2 pairs of date ranges are read from the console in the format: yyyy-mm-dd;
For example, if the two dates are
2020-01-05
2020-03-31
and
2020-01-05
2020-03-20
the program should find the days between 2020-01-05 and 2020-03-20. However, it doesn't work. I would like to ask how can I fix this?
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.Scanner;
public class Dates {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String a = sc.nextLine();
String b = sc.nextLine();
String c = sc.nextLine();
String d = sc.nextLine();
LocalDate ldt1 = LocalDate.parse(a);
LocalDate ldt2 = LocalDate.parse(b);
LocalDate ldt3 = LocalDate.parse(c);
LocalDate ldt4 = LocalDate.parse(d);
System.out.println(ChronoUnit.DAYS.between(ldt1,ldt2,ldt3,ldt4));
}
}
It’s a little more complicated than that (not badly).
String i1StartStr = "2020-01-05";
String i1EndStr = "2020-03-31";
String i2StartStr = "2020-01-05";
String i2EndStr = "2020-03-20";
LocalDate i1Start = LocalDate.parse(i1StartStr);
LocalDate i1End = LocalDate.parse(i1EndStr);
LocalDate i2Start = LocalDate.parse(i2StartStr);
LocalDate i2End = LocalDate.parse(i2EndStr);
if (i1End.isBefore(i1Start) || i2End.isBefore(i2Start)) {
System.out.println("Not proper intervals");
} else {
long numberOfOverlappingDates;
if (i1End.isBefore(i2Start) || i2End.isBefore(i1Start)) {
// no overlap
numberOfOverlappingDates = 0;
} else {
LocalDate laterStart = Collections.max(Arrays.asList(i1Start, i2Start));
LocalDate earlierEnd = Collections.min(Arrays.asList(i1End, i2End));
numberOfOverlappingDates = ChronoUnit.DAYS.between(laterStart, earlierEnd);
}
System.out.println("" + numberOfOverlappingDates + " days of overlap");
}
Output from the code as it stands here is:
75 days of overlap
I have also used better variable names and have introduced validation of the intervals that the user inputs.
I know I was supposed to add some explanation here, but frankly, I find the code using java.time so clear to read in itself, I don’t know what needs to be explained. If you want the number of days inclusive of both start and end dates, remember to add 1 to the return value from ChronoUnit.DAYS.between(). Please follow up in the comments and let me know what further explanation will be appropriate.
Related
I have created a To-Do-List program that records tasks input by a user. For each task, the user must input the name, date, etc.
When the user selects "5" from the menu, the program will sort these tasks by their date. I need to sort all tasks based on the ascending order of the task’s date and time, i.e., the tasks with earlier date and time will be listed before the tasks with later date and time, and display the sorted list.
When I run my code however, I receive these errors:
Exception in thread "main" java.lang.IllegalArgumentException: Cannot format given Object as a Date
at java.base/java.text.DateFormat.format(DateFormat.java:338)
at java.base/java.text.Format.format(Format.java:158)
at ToDoList.lambda$0(ToDoList.java:238)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540)
at ToDoList.sortTasks(ToDoList.java:238)
at ToDoList.main(ToDoList.java:106)
Here is my code so far: ( The sortTasks() is at the bottom )
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;
class Task{
private String theTitle;
private Date theDate;
private String theTime;
private String theLocation;
private String theDuration;
private String theCategory;
SimpleDateFormat format=new SimpleDateFormat("dd/MM/yyyy");
Task(String title, Date date, String time, String location, String duration, String category) {
theTitle = title;
theDate = date;
theTime = time;
theLocation = location;
theDuration = duration;
theCategory = category;
}
public String getTitle() {
return theTitle;
}
public Date getDate() {
return theDate;
}
public String getTime() {
return theTime;
}
public String getLocation() {
return theLocation;
}
public String getDuration() {
return theDuration;
}
public String getCategory() {
return theCategory;
}
public String getItem() {
return theTitle + ", " + format.format(theDate) + ", " + theTime + ", " + theLocation + ", " + theDuration + ", " + theCategory;
}
}
public class ToDoList {
public Task myTaskObj;
SimpleDateFormat format=new SimpleDateFormat("dd/MM/yyyy");
private static List<String> currentList = new ArrayList<String>();
public ToDoList() {
}
public static void main (String[] args) throws ParseException {
ToDoList listObj = new ToDoList();
int menuItem = -1;
while (menuItem != 7) {
menuItem = listObj.printMenu();
switch (menuItem) {
case 1:
listObj.addItem();
break;
case 2:
listObj.removeItem();
break;
case 3:
listObj.removeAllTasks();
break;
case 4:
listObj.showList();
break;
case 5:
listObj.sortTasks();
break;
case 6:
listObj.searchTasks();
break;
case 7:
System.out.println("Goodbye!");
default:
System.out.println("Enter a valid option");
}
}
}
public int printMenu() {
Scanner scanner = new Scanner(System.in);
System.out.println();
System.out.println("----------------------");
System.out.println("Main Menu");
System.out.println("----------------------");
System.out.println("1. Add a task");
System.out.println("2. Delete a task");
System.out.println("3. Delete all tasks");
System.out.println("4. List all tasks");
System.out.println("5. Sort tasks by date");
System.out.println("6. Search for a task");
System.out.println("7. Exit the program");
System.out.println();
System.out.print("Enter choice: ");
int choice = scanner.nextInt();
return choice;
}
public void showList() {
System.out.println();
System.out.println("----------------------");
System.out.println("To-Do List");
System.out.println("----------------------");
int number = 0;
for (String item : currentList) {
System.out.println(++number + ". " + item);
}
System.out.println("----------------------");
}
public void addItem() throws ParseException {
System.out.println("Add a task");
System.out.println("----------------------");
System.out.print("Enter the task title: ");
Scanner scanner = new Scanner(System.in);
String title = scanner.nextLine();
System.out.print("Enter the task date (dd/mm/yyyy): ");
Scanner scanner2 = new Scanner(System.in);
Date date=format.parse(scanner2.next());
System.out.print("Enter the task time: ");
Scanner scanner3 = new Scanner(System.in);
String time = scanner3.nextLine();
System.out.print("Enter the task location: ");
Scanner scanner4 = new Scanner(System.in);
String location = scanner4.nextLine();
System.out.println("Enter the task duration (optional - press enter to skip): ");
Scanner scanner5 = new Scanner(System.in);
String duration = scanner5.nextLine();
System.out.println("Enter the task category (optional - press enter to skip): ");
Scanner scanner6 = new Scanner(System.in);
String category = scanner6.nextLine();
myTaskObj = new Task(title, date, time, location, duration, category);
String theItem = myTaskObj.getItem();
currentList.add(theItem);
System.out.println("Task Added!");
}
public void removeItem() {
System.out.println("Delete a task");
System.out.println("----------------------");
Scanner scanner = new Scanner(System.in);
System.out.print("What do you want to remove? (Enter number): ");
int index = scanner.nextInt();
if((index-1)<0 || index>currentList.size()) {
System.out.println("Wrong index number! Please enter in range of 1 to "+currentList.size());
}else {
currentList.remove(index-1);
}
System.out.println("----------------------");
System.out.println("Task Removed!");
}
public void removeAllTasks() {
System.out.println("Remove all tasks");
System.out.println("----------------------");
showList();
Scanner keyboard = new Scanner(System.in);
System.out.print("Are you sure you'd like to delete all tasks? 'Yes' or 'No': ");
String choice = keyboard.nextLine();
if(choice.equals("Yes")) {
currentList.removeAll(currentList);
System.out.println("All tasks deleted!");
}
else
if(choice.equals("No"))
System.out.println("Tasks not deleted");
}
public void sortTasks() {
System.out.println("Sorted tasks by date (earliest first): ");
Collections.sort(currentList);
currentList.forEach(action-> System.out.println(format.format(action)));
}
}
First, organize your code so it is easier to deal with. Put each class in its own .java file. Use proper indenting to show hierarchy of code. Your IDE can help with that.
And keep in mind separation of concerns. Your ToDoList class should be focused on maintaining valid state regarding a list of Task objects. The ToDoList class should not know anything about interacting with users on a console. For that user interaction, create a separate class.
Looking at the Task class, you should never use the legacy classes java.util.Date, java.sql.Date, and SimpleDateFormat. They were supplanted years ago by the java.time classes with the unanimous adoption of JSR 310. For a moment as seen in UTC, use Instant. For a date-only value without a time-of-day and without a time zone, use LocalDate. For parsing/generating text representing those values, use DateTimeFormatter.
For booking future appointments and such, we must store the date and time-of-day separate from a time zone. Politicians frequently change the offset used by the time zone(s) of their jurisdiction. So 3 PM next January 23rd may not be the same moment then as we would expect now.
So your Task class needs a pair of member fields: LocalDateTime for the date with the time-of-day, plus a ZoneId time zone object. I assume you meant for this to be when the task should start, since you also have an option duration field.
And speaking of duration, Java has a class for that, Duration. It represents a span-of-time unattached to the timeline, on a scale of 24-hour-generic-days, hours, minutes, and fractional seconds.
The formatter should not be hard-coded on your Task class. Instead, the calling method that is using Task objects should pass a Locale object along with a FormatStyle to automatically localize the display of the date-time value. Even better, one could argue that generating formatted date-time strings should not even be the job of the Task class. The task object should just return the projected moment when the task is expected to start, returning a ZonedDateTime object by applying the stored ZoneId object to the stored LocalDateTime object.
Here is the method to applying the ZoneId to LocalDateTime to determine a moment (a point on the timeline) in the form of a ZonedDateTime object.
public ZonedDateTime projectedStartingMoment ( )
{
ZonedDateTime zdt = this.startDateTime.atZone( this.zoneId );
return Objects.requireNonNull( zdt );
}
➥ This on-the-fly generated ZonedDateTime object is also what we need to sort theses tasks, the original purpose of your question. To sort the Task objects, we will implement the Comparable interface, which requires we write a compareTo method. In our compareTo, we generate the ZonedDateTime object, and compare that for sorting. Different tasks could have different time zones, so we cannot just compare the stored LocalDateTime objects.
// Implement `Comparable` interface.
#Override
public int compare ( Task task1 , Task task2 )
{
return task1.projectedStartingMoment().compareTo( task2.projectedStartingMoment() );
}
Here is a table to help you keep straight these various date-time types.
We ignore the location and category fields, as they are not germane to the question of sorting by date.
We need to be able to differentiate one Task definitively from another. In real work, we would likely have a primary key used by a database to track each task record. Often such a primary key is either an serial integer number or a UUID. Here we use a UUID. We override Object::equals and Object::hashCode to use this UUID identifier value. These methods may be used by our SortedSet collection of Task objects.
No need to prefix your member fields with the.
So that Task class looks something like this. By the way, the new Records feature coming in Java 15 could be used for this class, but we'll not do that here as Java 15 is not yet released.
package work.basil.example;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Comparator;
import java.util.Objects;
import java.util.UUID;
public class Task
implements Comparable < Task >
{
// Member fields.
private UUID id;
private String title;
private LocalDateTime startDateTime;
private ZoneId zoneId;
private Duration duration;
// Constructor
public Task ( UUID id , String title , LocalDateTime startDateTime , ZoneId zoneId , Duration duration )
{
this.id = id;
this.title = title;
this.startDateTime = startDateTime;
this.zoneId = zoneId;
this.duration = duration;
}
// Logic
public ZonedDateTime projectedStartingMoment ( )
{
ZonedDateTime zdt = this.startDateTime.atZone( this.zoneId );
return Objects.requireNonNull( zdt );
}
public ZonedDateTime projectedEndingMoment ( )
{
ZonedDateTime zdt = this.startDateTime.atZone( this.zoneId ).plus( this.duration ); // Half-Open approach, for spans-of-time that neatly abut one another without gaps.
return Objects.requireNonNull( zdt );
}
// Accessors
// Getters only, immutable object.
public UUID getId ( ) { return this.id; }
public String getTitle ( ) { return this.title; }
public LocalDateTime getStartDateTime ( ) { return this.startDateTime; }
public ZoneId getZoneId ( ) { return this.zoneId; }
public Duration getDuration ( ) { return this.duration; }
// Object overrides.
#Override
public String toString ( )
{
return "Task{ " +
"id=" + id +
" | title='" + title + '\'' +
" | startDateTime=" + startDateTime +
" | zoneId=" + zoneId +
" | duration=" + duration +
" | projectedStartingMoment=" + projectedStartingMoment() +
" }";
}
#Override
public boolean equals ( Object o )
{
if ( this == o ) return true;
if ( o == null || getClass() != o.getClass() ) return false;
Task task = ( Task ) o;
return getId().equals( task.getId() );
}
#Override
public int hashCode ( )
{
return Objects.hash( getId() );
}
#Override
public int compareTo ( Task other )
{
return this.projectedStartingMoment().compareTo( other.projectedStartingMoment() );
}
}
Next, we collect objects of that Task class into a ToDoList. The ToDoList class in your Question is mixing concerns, dealing with user interactions, and dealing with presentation. Both of those belong in your app class. Think of it this way, if you were to later add a GUI to your app in addition to the console user-interface, your ToDoList::showList would be a misfit, irrelevant. That tells us the "showList" work does not belong in the ToDoList class.
At this point our ToDoList class could simply be a List or Set, with no need for us to define our own class. But in real work, this class would likely have additional duties. So we will proceed in creating that class.
package work.basil.example;
import java.util.*;
public class ToDoList
{
private SortedSet < Task > tasks;
// Constructors
public ToDoList ( )
{
this.tasks = new TreeSet <>();
}
public ToDoList ( Collection < Task > tasks )
{
this(); // Call other constructor
this.tasks.addAll( tasks );
}
// Logic
public boolean addTask ( Task task )
{
Objects.requireNonNull( task ); // Fail fast. In real work, pass a message for the exception.
boolean result = this.tasks.add( task );
return result;
}
public boolean addTasks ( Collection tasks )
{
return this.tasks.addAll( Objects.requireNonNull( tasks ) );
}
public boolean remove ( Task task )
{
return this.tasks.remove( Objects.requireNonNull( task ) );
}
public void removeAll ( )
{
this.tasks.clear();
}
public List < Task > getTasksSortedByProjectedStartingMoment ( )
{
// Make a copy of our `SortedSet`, to be separate from our own here.
// This way the calling method can do what they want, as can this class,
// while not stepping on each other's feet.
Objects.requireNonNull( this.tasks ); // Paranoid check.
return List.copyOf( this.tasks );
}
}
Let's harness those classes to see them in action. I will use the beginnings of what can be your new app (main) class for interacting with user on console. But I will not do all the user-interaction code, as that is not germane to the Question. Here I just instantiate a few Task objects, put them in a ToDoList, and get back a list sorted by date.
To finally answer your Question, we call our ToDoList::getTasksSortedByProjectedStartingMoment method.
List < Task > tasksSorted = this.toDoList.getTasksSortedByProjectedStartingMoment();
Full example code.
package work.basil.example;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.Month;
import java.time.ZoneId;
import java.util.List;
import java.util.UUID;
public class ToDoListEditorConsole
{
private ToDoList toDoList;
public static void main ( String[] args )
{
ToDoListEditorConsole app = new ToDoListEditorConsole();
app.launch();
}
private void launch ( )
{
this.toDoList = new ToDoList();
this.demo();
}
private void demo ( )
{
// Make a few `Task` objects. All on the same day in the same zone, but different time-of-day.
// Notice that our time-of-day values are *not* in chronological order.
List < Task > tasks = List.of(
new Task(
UUID.fromString( "98399344-bb31-11ea-b3de-0242ac130004" ) ,
"Eat apple" ,
LocalDateTime.of( 2021 , Month.JANUARY , 23 , 12 , 30 , 0 , 0 ) ,
ZoneId.of( "Africa/Tunis" ) , Duration.ofHours( 1 )
) ,
new Task(
UUID.fromString( "1e4ded04-bb32-11ea-b3de-0242ac130004" ) ,
"Eat banana" ,
LocalDateTime.of( 2021 , Month.JANUARY , 23 , 20 , 00 , 0 , 0 ) ,
ZoneId.of( "Africa/Tunis" ) , Duration.ofHours( 1 )
) ,
new Task(
UUID.fromString( "010fcde8-bb32-11ea-b3de-0242ac130004" ) ,
"Eat corn" ,
LocalDateTime.of( 2021 , Month.JANUARY , 23 , 15 , 00 , 0 , 0 ) ,
ZoneId.of( "Africa/Tunis" ) , Duration.ofMinutes( 30 )
)
);
this.toDoList.addTasks( tasks );
List < Task > tasksSorted = this.toDoList.getTasksSortedByProjectedStartingMoment();
System.out.println( "Result:" );
System.out.println( tasksSorted );
System.out.println( "« fin »" );
}
}
When run, notice how the banana and corn tasks (2nd & 3rd) switched places, now sorted chronologically.
Result:
[Task{ id=98399344-bb31-11ea-b3de-0242ac130004 | title='Eat apple' | startDateTime=2021-01-23T12:30 | zoneId=Africa/Tunis | duration=PT1H | projectedStartingMoment=2021-01-23T12:30+01:00[Africa/Tunis] }, Task{ id=010fcde8-bb32-11ea-b3de-0242ac130004 | title='Eat corn' | startDateTime=2021-01-23T15:00 | zoneId=Africa/Tunis | duration=PT30M | projectedStartingMoment=2021-01-23T15:00+01:00[Africa/Tunis] }, Task{ id=1e4ded04-bb32-11ea-b3de-0242ac130004 | title='Eat banana' | startDateTime=2021-01-23T20:00 | zoneId=Africa/Tunis | duration=PT1H | projectedStartingMoment=2021-01-23T20:00+01:00[Africa/Tunis] }]
« fin »
I suggest the main problem you're facing here is that you are storing the tasks as strings rather than as Task objects. If you stored them correctly then a lot of the actions would be significantly easier.
So, change your list to:
class ToDoList {
private final List<Task> tasks = new ArrayList<>();
...
}
Then sorting becomes pretty trivial. For example it could look like:
public void sortTasks(Comparator<Task> order) {
tasks.sort(order);
}
And the code reacting to the user might look like:
case 5: toDoList.sortTasks(Comparator.comparing(Task::getDate).thenComparing(Task::getTime));
Which would make it trivial to add options to sort by other criteria such as sortTasks(Comparator.comparing(Task::getTitle)).
This should also make output easier to read as it could be embedded in the task's toString method.
Getting the model right is fundamental to writing cleaner code.
I have trouble finding elements, here is my code:
public static void main(String[] args) {
BufferedReader br = getFileReader("reader.csv");
ArrayList<Monitoring> col = getCollection(br);
//sort the collection on 'beginTime'
for (Monitoring x : col)
System.out.println(x.toString());
BeginTimeComparator beginTime = new BeginTimeComparator();
Collections.sort(col,beginTime);
System.out.println("Begin time:");
for (Monitoring x : col)
System.out.println(x.toString());
This is the part I have trouble with, I don't know how to search en get back the object with endTime 2015-03-10.
BTW this is one line of cvs data:
UnitId;BeginTime;EndTime;Type;Min;Max;Sum
14100072;2015-03-10 07:12:20;2015-03-10 7:13:20;Gps/GpsAccuracyGyroBias;0;0;0
//find the amount of elements that were sent on 'endTime' = 2015-03-10 (just the date)
EndTimeComparator endTime = new EndTimeComparator();
String findThis = "2015-03-10";
Collections.sort(col, endTime);
for(Monitoring x : col){
if(x.getEndTime().equals(findThis)){
System.out.println("Here is 'endTime= 2015-03-10' :");
System.out.println(x.toString());
}
}
I have tried this but both didn't work:
int index = Collections.binarySearch(col, findThis.toString(), null);
System.out.println("Here is 'endTime= 2015-03-10' :");
System.out.println(index);
Guessing that getEndTime() returns a LocalDateTime you can't compare a string with a type of LocalDateTime. You could try to parse the LocalDateTime to LocalDate and fill the 'findThis' variabel with a type of LocalDate.
Because code says more than a 1000 words:
EndTimeComparator endTime = new EndTimeComparator();
Collections.sort(col, endTime);
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate findThis = LocalDate.parse("2015-03-10", dtf);
System.out.println("Here is 'endTime= 2015-03-10' :");
for (Monitoring x : col) {
if (x.getEndTime().toLocalDate().equals(findThis)) {
System.out.println(x.toString());
}
}
You need to provide Comparator for that null or Monitoring should implement comparable (both of them should compare items by time field that you need).
Collections.binarySearch(col, findThis.toString(), null);
According to the example data you provided
UnitId;BeginTime;EndTime;Type;Min;Max;Sum
14100072;2015-03-10 07:12:20;2015-03-10 7:13:20;Gps/GpsAccuracyGyroBias;0;0;0
endTime is "2015-03-10 7:13:20", not "2015-03-10", so using equals will not work. Instead, you could try using startsWith:
String findThis = "2015-03-10";
for (Monitoring x : col) {
if (x.getEndTime().startsWith(findThis)) {
System.out.println("Here is 'endTime= 2015-03-10': ");
System.out.println(x.toString());
}
}
Or even better: Instead of storing the begin and end times as strings, convert them to Date objects or similar when you read the objects from CSV.
I'm fairly new to programming in general and need some help.
I am using the Java.util.TimeZone to retrieve the IDs (city names) and their time zones. I am using a hashmap to implement this. I have put the city names and the time zones in the map and I am now trying to ask the user to enter a city they wish to get the time zone of.
However, in my loop I have a validation check to make sure the city name is in the hashmap. Not only is it not working but the loop also does not break. It correctly puts out the time it is currently but not the correct timezone for the city (I have typed various city names and all have about the same timezone). After printing out the local time it is in the city the user can choose to end the program by "saying yes".
If the user enters yes then the loop should break and the the program should end. If they enter anything else it should continue.
Could someone please help me fix this! Here is my code.
import java.util.*;
import java.util.TimeZone;
import java.util.Date;
import java.text.DateFormat;
import java.util.HashMap;
class Maps {
public static void main(String[] args) {
String[] Zone = TimeZone.getAvailableIDs();
int i = 0;
for (i = 0; i < Zone.length; i++) {
String zone1 = Zone[i].replaceAll("_", " ");
if (zone1.indexOf('/') != -1) {
zone1 = zone1.substring(zone1.indexOf('/') + 1);
}
TimeZone tz = TimeZone.getTimeZone(zone1);
HashMap hm = new HashMap();
HashMap<String, Integer> map = new HashMap<String, Integer>();
hm.put(zone1, tz);
// System.out.println(hm);
while (hm != null) {
java.util.Scanner input = new java.util.Scanner(System.in);
System.out.println("City?");
String city = input.nextLine();
boolean CityExist = hm.containsKey(city);
if (CityExist == true) {
System.out
.println("I can not find a match to the city, sorry. ");
break;
}
TimeZone tz2 = TimeZone.getTimeZone(city);
DateFormat timeFormatter = DateFormat.getTimeInstance();
Date now = new Date();
System.out.println("Here: " + timeFormatter.format(now));
System.out.print("Local Time: ");
timeFormatter.setTimeZone(tz2);
System.out.println(timeFormatter.format(now));
System.out
.println("If you would like to quit please enter yes: ");
String user = input.nextLine();
if (user.equals("yes") || user.equals("Yes")) {
break;
}
}
}
}
}
Looks like you have the logic inverted: if CityExist then there was no match?
Please format your code next time.
Doing this, you will see that your first for loop is not closed and you are doing while loop still inside your for loop.
Solution, put the close bracket } before while loop.
java program to accept any format of date as input and print the month,
Is it possible
I tried the following,any other alternative ways/ideas??
import java.text.*;
import java.util.*;
public class PrintMonth3{
public static void main(String args[])throws Exception{
String patterns[]={"dd.MM.yyyy","dd.MM.yy","dd.MMM.yyyy","dd.MMM.yy","d.MM.yyyy"};
String input="4.06.2011";
for(int i=0;i<patterns.length;i++)
doPrintMonth(patterns[i],input);
System.out.println("\nNot a valid date format..");
}
public static void doPrintMonth( String pattern,String input ) {
try{
SimpleDateFormat sdf=new SimpleDateFormat(pattern);
Date output=sdf.parse(input);
String mon[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
int m=output.getMonth();
System.out.println("\n\t" + mon[m] );
System.exit(0);
}
catch(Exception e){}
}
}
No, it's not. How would it distinguish 01/02/2011 (dd/MM/yyyy) and 01/02/2011 (MM/dd/yyyy)?
Within reason, yes. Here's a working example that accepts a variety of formats.
I'm assuming a German / European format like this:
DD. MM. YYYY HH:MM:SS:MMMM
(which means that I can't match any date format where the month comes first)
Here's the class:
public class VariableDateParser {
private static final Pattern DATE_PATTERN = Pattern
.compile("((?:(?:\\d+(?:[./]\\s*)?)+)?)\\s*((?:(?:\\d+[:]?)+)?)");
public Date getDate(final String dateString) {
final Calendar calendar = Calendar.getInstance();
final Matcher matcher = DATE_PATTERN.matcher(dateString);
if (matcher.matches()) {
final String dateGroup = matcher.group(1).trim();
if (!"".equals(dateGroup)) {
final Iterator<Integer> fields = Arrays.asList(
Calendar.DATE, Calendar.MONTH, Calendar.YEAR).iterator();
final String[] items = dateGroup.split("\\D+");
for (final String item : items) {
if ("".equals(item))
break;
else if (fields.hasNext()) {
final Integer field = fields.next();
calendar.set(field, Integer.parseInt(item) -
// months are 0-based, grrrr!!!
(field.equals(Calendar.MONTH) ? 1 : 0));
} else {
throw new IllegalArgumentException(
"Bad date part: " + dateGroup);
}
}
}
final String timeGroup = matcher.group(2).trim();
if (!"".equals(timeGroup)) {
final Iterator<Integer> fields = Arrays.asList(
Calendar.HOUR, Calendar.MINUTE, Calendar.SECOND,
Calendar.MILLISECOND).iterator();
final String[] items = timeGroup.split("\\D+");
for (final String item : items) {
if ("".equals(item))
break;
else if (fields.hasNext()) {
final Integer field = fields.next();
calendar.set(field, Integer.parseInt(item));
} else {
throw new IllegalArgumentException(
"Bad time part: " + timeGroup);
}
}
}
} else
throw new IllegalArgumentException(
"Bad date string: " + dateString);
return calendar.getTime();
}
}
Test Code:
public static void main(final String[] args) {
VariableDateParser parser = new VariableDateParser();
DateFormat df = DateFormat.getDateTimeInstance(
DateFormat.MEDIUM, DateFormat.LONG, Locale.GERMAN);
System.out.println(df.format(parser.getDate("11")));
System.out.println(df.format(parser.getDate("11. 10.")));
System.out.println(df.format(parser.getDate("11. 10. 4")));
System.out.println(df.format(parser.getDate("11. 10. 2004")));
System.out.println(df.format(parser.getDate("11. 10. 2004 11")));
System.out.println(df.format(parser.getDate("11. 10. 2004 11:35")));
System.out.println(df.format(parser.getDate("11. 10. 2004 11:35:18")));
System.out.println(df.format(parser.getDate("11. 10. 2004 11:35:18:123")));
System.out.println(df.format(parser.getDate("11:35")));
System.out.println(df.format(parser.getDate("11:35:18")));
System.out.println(df.format(parser.getDate("11:35:18:123")));
}
Output:
11.05.2011 15:57:24 MESZ
11.10.2011 15:57:24 MESZ
11.10.0004 15:57:24 MEZ
11.10.2004 15:57:24 MESZ
11.10.2004 23:57:24 MESZ
11.10.2004 23:35:24 MESZ
11.10.2004 23:35:18 MESZ
11.10.2004 23:35:18 MESZ
01.05.2011 13:35:24 MESZ
01.05.2011 13:35:18 MESZ
01.05.2011 13:35:18 MESZ
Note:
This is a quick proof of concept, not a serious attempt of writing such a class. This will match many invalid formats and ignore many valid ones.
For a wide range of formats, yes it is possible. For any format, no it is not. Consider the simple problem of British vs American dates e.g is 03/04/10 the third of april or the fourth of march?
No, it is not possible.
Proof by counter example: 10/11/12. This is a 'valid' format... but what is the month?
It's possible only if you also tell it what the format is, for instance with the Locale.
Technically its not but what you can do is provide some options to get the user to choose their format. If you are writing this in a GUI then you might want to use radio buttons and put them in a radio group. Otherwise if this is just for use within the compiler (such as a school program) then just use a switch statement like so:
Scanner kbReader = new Scanner(System.in);
String format = kbReader.next();//they might enter mm/dd/yy or any format you want.
switch(format)
{
case "mm/dd/yy": //do coding here
break;
case "dd/mm/yy": //do coding here
break;
}
just like that or you could just use a series of if-else statements because that is basically what a switch statement is.
I have a family tree app which allows you to build nodes. I am stuck on a problem which requires editing a members date of birth. The date of birth is just a string in the following format dd-mm-yyyy. My problem arises when checking if the date of birth is valid (i.e. any parent cannot be younger than a child). So if the node has both parents and children and user selects to edit it's date of birth, the function must continuously check to see whether an age between the two dates has been added. The problem I am having is getting this continual check to occur using the methods I have defined. I'm hoping someone understands the isue and can help. Note checkDOb also sets the dob too. its bad naming on my part.
here is the code:
private void dateCheck(FamilyMember node) {
String dob = enterDateOfBirth();
if (node.hasChildren()) {
node.setDob(dob);
checkDob(node, node.getOldestChild(), 0);
}
FamilyMember parent = null;
if (node.hasMother() && node.hasFather()) {
if (node.getMother().getAge() > node.getFather().getAge()) {
parent = node.getFather();
} else {
parent = node.getMother();
}
checkDob(parent, node, 1);
} else {
//single parent
if (node.hasMother()) {
parent = node.getMother();
checkDob(parent, node, 1);
}
if (node.hasFather()) {
parent = node.getFather();
checkDob(parent, node, 1);
}
}
}
private void checkDob(FamilyMember parent, FamilyMember child, int member) {
out.println(parent.getYear());
out.println(child.getYear());
while (parent.getYear() > child.getYear()) {
out.println("Invalid Date - The Oldest Child of " + parent.getFullName()
+ "(" + child.getFullName() + ")\n cannot older than his/her parents. Try Again.");
out.println();
if (member == 0) {
parent.setDob(enterDateOfBirth());
}
if (member == 1) {
child.setDob(enterDateOfBirth());
}
}
}
private String enterDateOfBirth() {
out.print("Enter Year Of Birth (0 - 2011): ");
String y = in.nextLine();
out.print("Enter Month Of Birth (1-12): ");
String m = in.nextLine();
if (m.trim().equals("")) {
m = "0";
}
if (m.length() == 1) {
m = "0" + m;
}
m += "-";
out.print("Enter Date of Birth (1-31): ");
String d = in.nextLine();
if (d.trim().equals("")) {
d = "0";
}
if (d.length() == 1) {
d = "0" + d;
}
d += "-";
String dob = d + m + y;
while (!DateValidator.isValid(dob)) {
out.println("Invalid date. Try again.");
dob = enterDateOfBirth();
}
return (dob);
}
Thanks in advance.
Well the standard way to parse Dates is using SimpleDateFormat. But I don't think that will help in your case you so I won't go there.
But you should use Date objects (or, as others will say: use JodaTime's DateTime object) when you are talking about Dates, it makes things easier.
make Date the type of dob
and exchange this code:
String dob = d + m + y;
for this:
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, Integer.parseInt(y));
cal.set(Calendar.MONTH, Integer.parseInt(m)-1);
cal.set(Calendar.DATE, Integer.parseInt(d));
Date dob = cal.getTime();
(you should lose all the if (m.length() == 1) stuff, because Strings with leading zeroes will be parsed as octal values)
Now you can just validate that parentBirthDate.compareTo(childBirthDate)>0
Also, to be more precise you should truncate all the fields that are smaller than day:
cal.set(Calendar.HOUR, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
Also: don't use System.out.println(), use a logging framework like Log4J or SLF4J.
Oh, BTW, validating that the child is younger than the parent won't be enough. You will probably have to validate that the difference is 12 years or more :-)
It can be smt like
//return true if one of arguments is true!
private boolean bornBefore(FamilyMember first, FamilyMember second){
if(first == null || second == null){
return true;
}
return /*your magic date comaparator*/;
}
private boolean validDate(FamilyMember node, MagicDate date) {
return bornBefore(node, node.getOldestChild())
&& bornBefore(node.getFather(), node)
&& bornBefore(node.getMother(), node);
}
}
You should decouple your validation and data entry. To start of you have your tree model with the current values and a new string that you want to enter in to change a value.
bool checkDOB(String date, FamilyMember node) {
//return true if date is more recent than any parents of node and
//older than any children of node
}
Now that you have a stand alone validation method, you should call it anytime you are about to add a new node or edit one. Do not change any values in the actual data model until it has been validated This means your tree will always be in a valid state and an edit is just a local operation.