how to fetch next 4 weekdays name from a particular day? - java

i need to get next few days name from a particular day. like given day name is Friday and i need to get next 4 like Saturday, Sunday, Monday and Tuesday.

Try this .....
String[] days=new String[] {"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
private ArrayList<String> getNextFourDays(String day)
{
int index=-1;
int count=0;
for(int i=0;i<days.length;i++) {
if(days[i].equalsIgnoreCase(day)) {
index=i;
break;
}
}
if(index==-1)
{
return null;
}
ArrayList<String> nextFourDays=new ArrayList<>();
for(int j=index+1;count<4;j++) {
if(j>=days.length) {
j=0;
}
nextFourDays.add(days[j]);
count++;
}
return nextFourDays;
}
Note: it will return null if the invalid day is passed other than the string[] days valid and case has no effect

In this case, I would use the java.time DayOfWeek enum for type safety instead of strings suggested by other answers.
If you are using kotlin you can even define an extension function like this:
fun DayOfWeek.getFollowingDays(n: Int): List<DayOfWeek> {
val list: MutableList<DayOfWeek> = mutableListOf()
var tempDay = this
for (i in 0 until n) {
tempDay = tempDay.plus(1)
list.add(tempDay)
}
return list
}
Then you can call the extension function like this:
DayOfWeek.FRIDAY.getFollowingDays(4)
and the result would be
[SATURDAY, SUNDAY, MONDAY, TUESDAY]
The advantage of using enum instead of a string is that the compiler will catch any errors for you and your app will not crash/have undesired behaviour at runtime. If day is represented as a string you can pass any possible string (like "Invalid Day!") which might cause the program to act unexpectedly at runtime. However, by using enums there is no possible way to misuse it, you need to call it on a day defined by the enum otherwise the app won't build.

It's aready answered but you can do it with much cleaner code and moderner APIs: OneLiner
import java.time.DayOfWeek;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class Test {
public static void main(String[] args) {
List<DayOfWeek> nextDaysList = IntStream.range(1, 5).mapToObj(x -> DayOfWeek.FRIDAY.plus(x))
.collect(Collectors.toList());
}
}

Related

Compare multiple calendar and find which is the closer to run or is active now using starting and ending

my request for help is kinda weird. I'll try to be short.
I have this line where i parse a schedule of Ex. 18:00-19:00 ; 22:00-23:00
The schedule 18:00 to 19:00 is one object and the other 22:00 to 23:00 is seperated by ";". Which mean you can add infinite schedules.
Now i parse this line using:
Arrays.asList(schedule.replaceAll("\\s", "").split(";")).forEach(s -> _schedules.add(new ScheduleCalendar(Integer.parseInt(s.split("-")[0].split(":")[0]), Integer.parseInt(s.split("-")[0].split(":")[1]), Integer.parseInt(s.split("-")[1].split(":")[0]), Integer.parseInt(s.split("-")[1].split(":")[1]))));
And i use this class
public static class ScheduleCalendar
{
private final Calendar[] _calendar = new Calendar[2];
public ScheduleCalendar(final int startingHour, final int startingMinute, final int endingHour, final int endingMinute)
{
final Calendar starting = Calendar.getInstance();
starting.set(Calendar.HOUR_OF_DAY, startingHour);
starting.set(Calendar.MINUTE, startingMinute);
starting.set(Calendar.SECOND, 0);
starting.set(Calendar.MILLISECOND, 0);
_calendar[0] = starting;
final Calendar ending = Calendar.getInstance();
ending.set(Calendar.HOUR_OF_DAY, endingHour);
ending.set(Calendar.MINUTE, endingMinute);
ending.set(Calendar.SECOND, 0);
ending.set(Calendar.MILLISECOND, 0);
_calendar[1] = ending;
}
public boolean isBefore(final ScheduleCalendar schedule)
{
return false;
}
public Calendar[] getCalendars()
{
return _calendar;
}
public boolean isNow()
{
return _calendar[0].getTimeInMillis() > System.currentTimeMillis() && _calendar[1].getTimeInMillis() < System.currentTimeMillis();
}
}
and finally store in
private final List<ScheduleCalendar> _schedules = new ArrayList<>();
Now i want to make a method which retrieve the closest schedule or active if is possible.
Is there any fancy and fast way using java 8-16 to reproduce this code without having to write so long code? Any library maybe or so?
There is no good reason to use Calendar if we are using java 8+
Suppose the time range 'from' < 'to', i.e. "23:00-01:00" is not allowed, using LocalTime with lambda function can greatly simplify the code.
The algorithm for finding closest or active:
Discard outdated time ranges ('from' > active time)
For those 'to' < active time, choose the one with max 'to' (closest)
If no time range in (2), for those 'from' < active time < 'to', choose the one with max 'from'.
Of course you may swap the ordering of 2 and 3 depends on your priority for closest vs active.
import java.time.LocalTime;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
public class Scheduler {
public static void main(String[] args) {
String values = "21:00-23:00;20:00-21:00;18:00-19:00;22:30-23:00";
LocalTime now = LocalTime.parse("22:00");
List<LocalTimeRange> timeRanges = Arrays.stream(values.split(";")).map(s -> {
String[] arr = s.split("-");
return new LocalTimeRange(LocalTime.parse(arr[0]), LocalTime.parse(arr[1]));
}).collect(Collectors.toList());
getClosetOrActive(timeRanges, now).ifPresentOrElse(System.out::println, () -> System.out.println("No time range match"));
}
private static Optional<LocalTimeRange> getClosetOrActive(List<LocalTimeRange> timeRanges, LocalTime activeTime) {
// Outdated range is discarded
List<LocalTimeRange> notOutdatedRanges = timeRanges.stream().
filter(timeRange -> !timeRange.getFrom().isAfter(activeTime)).collect(Collectors.toList());
// For range before active time, retrieve the one with 'to' closest to activeTime
Optional<LocalTimeRange> closet = notOutdatedRanges.stream().filter(localTimeRange -> localTimeRange.getTo().isBefore(activeTime))
.sorted(Comparator.comparing(LocalTimeRange::getTo).reversed()).findFirst();
if (closet.isPresent()) {
return closet;
}
// For range cover active time, retrieve the one with latest 'from'
return notOutdatedRanges.stream().filter(localTimeRange -> !localTimeRange.getTo().isBefore(activeTime))
.sorted(Comparator.comparing(LocalTimeRange::getFrom).reversed()).findFirst();
}
public static class LocalTimeRange {
private final LocalTime from;
private final LocalTime to;
public LocalTime getFrom() {
return from;
}
public LocalTime getTo() {
return to;
}
#Override
public String toString() {
return from + "-" + to;
}
public LocalTimeRange(LocalTime from, LocalTime to) {
this.from = from;
this.to = to;
}
}
}

Sort objects in List by String (dd/mm/yyyy)?

Can someone help me with this? I can't find any example..
I've created a Java Class called Subtaks with multiple fields. And i'm trying to sort a list of Subtasks. Firt I'm sorting the list alphabetically with one field called status; but if this field is the same i'm trying to sort it by another String field that containt a date with this format:
String resolutionDate = "18/09/2014"
I've implemented this method to sort it:
#Override
public int compareTo(Subtask o) {
if (this.status.equals(o.status))
return o.resolutiondate.compareTo(this.resolutiondate);
else
return this.status.compareTo(o.status);
}
I assume you want to sort by date so you'd either have to manually extract year, day and month and compare them or parse the date and compare the parsed dates.
For the first approach, you could use something like this:
String resolutionDateReordered = resolutionDate.replaceAll("(\\d+)/(\\d+)/(\\d+)","$3$2$1");
And then compare resolutionDateReordered. This assumes that the parts of the date have equal length, i.e. 2-digit day and month and 4 digit year and would reorder the string "18/09/2014" to "20140918", which then would be sortable by date.
This could be optimized by creating the pattern once and reusing it, e.g.
Pattern p = Pattern.compile( "(\d{2})/(\d{2})/(\d{4})" ); //pattern slightly changed to expect 2-digit day and month and 4-digit year.
and in your compare() method:
String resolutionDateReordered = p.matcher( resolutionDate ).replaceAll( "$3$2$1" );
As for the second approach you do something like this:
DateFormat df = new SimpleDateFormat("dd/MM/yyyy");
Date resolutionDateParsed = df.parse( resolutionDate );
And then compare resolutionDateParsed using Date's compareTo() method.
Depending on the size of the list, the first or second approach might be faster, but YMMV. For example, on my machine sorting a list of date strings having your format using the optimized version of the string reordering is approx. twice as fast as parsing first and comapring the dates, with 3.5 seconds vs. 7.4 seconds for 100k entries.
First you convert your String value of date("dd/mm/yyyy") to type of Date(java.util)
public class YourClassName implements Comparable<YourClassName> {
....
//return -1 for less than, 0 for equals, and 1 for more than
public compareTo(Subtask subTask) {
int result = 0;
result = getResolutionDate().compareTo(subTask.getResolutionDate());
if (result != 0)
{
return result;
}
result = getStatus().compareTo(subTask.getStatus());
if (result != 0)
{
return result;
}
...
}
}
Here is the SubTask class:
package com.test.main;
import java.util.Date;
public class Subtask implements Comparable<Subtask> {
private String status;
private Date resolutionDate;
public Subtask(String status, Date resolutionDate) {
super();
this.status = status;
this.resolutionDate = resolutionDate;
}
public String getStatus() {
return status;
}
public Date getResolutionDate() {
return resolutionDate;
}
#Override
public int compareTo(Subtask o) {
int compareToIgnoreCase = status.compareToIgnoreCase(o.getStatus());
return compareToIgnoreCase==0?resolutionDate.compareTo(o.getResolutionDate()):compareToIgnoreCase;
}
}
Main method:
public static void main(String args[]){
List<Subtask> arrayList = new ArrayList<>();
Calendar instance = Calendar.getInstance();
instance.setTime(new Date());
arrayList.add(new Subtask("test1", instance.getTime()));
instance.set(Calendar.MONTH, 11);
arrayList.add(new Subtask("test1", instance.getTime()));
instance.set(Calendar.MONTH, 5);
arrayList.add(new Subtask("test1", instance.getTime()));
Collections.sort(arrayList);
for (Subtask subtask : arrayList) {
System.out.println(subtask.getResolutionDate());
}
}

String array to multiple objects

I have a string array
String[] weekDays
weekDays represents days of week. for eg
{1, 2, 4} means Monday, Tuesday, Thusday
{2,5,6,7} means Tuesday, Friday, Saturday, Sunday
I have seven boolean representing 7 days of week and have to set true or false on the basis of weekDays.
My code
private static void setWeekDays(final Object object, final String[] weekDays) {
for (String day : weekDays) {
if( day.equalsIgnoreCase("1")) {
object.setMonday(true);
} else if( day.equalsIgnoreCase("2")) {
object.setTuesday(true);
} else if( day.equalsIgnoreCase("3")) {
object.setWednesday(true);
} else if( day.equalsIgnoreCase("4")) {
object.setThrusday(true);
} else if( day.equalsIgnoreCase("5")) {
object.setFriday(true);
} else if( day.equalsIgnoreCase("6")) {
object.setSaturday(true);
} else if( day.equalsIgnoreCase("7")) {
object.setSunday(true);
}
}
}
But it has so many if else statements and before performing this i explicitly set all booleans to be false.
Is there any other simple way to do the same thing? Any suggestion ??
I think you can try to use ENUM for this.
For example
public enum WeekDay {
MONDAY("1");
private String value;
private WeekDay(String value) {
this.value = value;
}
public static WeekDay find(String value) {
for (WeekDay weekDay : values()) {
if (weekDay.value.equals(value)) {
return weekDay;
}
}
}
So then you can use this ENUM as field of your DTO.
Define an Enum to be your days of the week:
enum DayOfWeek {
MONDAY, TUESDAY, etc.
}
Create a map to go from string to day:
Map<String, DayOfWeek> dayByString = new HashMap<String, DayOfWeek>();
Fill the map with all lookups you want, i.e.
dayByString.put("1", DayOfWeek.MONDAY);
dayByString.put("2", DayOfWeek.TUESDAY);
Now to look up the day just do:
DayOfWeek day = dayByString.get(str);
This will return null if there is no match - or the matching day of the week.
Now instead of your 7 booleans use an EnumSet:
Set<DayOfWeek> days = new EnumSet<DayOfWeek>(DayOfWeek.class);
Internally that will use a bitfield to represent the days so will be incredibly fast and space efficient.
To set the flag do days.add(day);
To unset it do days.remove(day);
To check if it is set do days.contains(day); or days.contains(DayOfWeek.MONDAY);.
private static void setWeekDays(EnumSet<DayOfWeek> set, final String[] weekDays) {
set.clear();
for (String day : weekDays) {
set.add(dayByString.get(day));
}
}
You are done, that's all you need.
EnumSet is the correct way to store this. There are other options but 7 booleans is flat out wrong.
You can try following:
Add following code in your DTO Object
List weekDaysList;
private void setWeekDays(String[] weekDays){
weekDaysList = Arrays.asList(weekDays);
}
private boolean isWeekdaySet(String weekday){
if (weekDaysList == null || weekDaysList.size() == 0){
return false;
}
return weekDaysList.contains(weekday);
}
update each of the getMonday, getTuesday method as follows:
public boolean getMonday() {
return isWeekdaySet("1");
}
public boolean getTuesday(){
return isWeekdaySet("2");
}
I hope this helps.
If the DTO class can NOT be modified, you could try to make a method mapping previously, and use reflection to call the target method, like this:
private static Method[] methods;
private static void init() throws Exception {
Class klass = BusTravelDetailDTO.class;
String[] methodNames = new String[]{null, "setMonday", "setTuesday", "setSunday"};
methods = new Method[methodNames.length];
for (int i = 0; i < methods.length; i++) {
if(methodNames[i] != null) {
methods[i] = klass.getMethod(methodNames[i], Boolean.class);
}
}
}
private static void setWeekDays(final Object object, final String[] weekDays) {
for (String day : weekDays) {
methods[Integer.parseInt(day)].invoke(object, Boolean.TRUE);
}
}
But, since you have only seven choices, if-else might be the most simple and efficient way.
If the DTO class can be modifie, use enum instead of seven boolean flags.

static methods that manipulates Date. multi threading issue

Friends,
I'm giving modified extract of my production code.
When running the following code, I'm getting "TestDateProblem: Problem with getYear method" though I'm executing the getDateEndOfDay by passing auditdate1.
I couldn't really solve this issue as the date is going correctly and I could see this in the logger in the catch block of my production code. I badly need your help.
This getDateEndOfDay method is called from many public methods and it may be possible that multiple threads are calling these static methods at the same time.
package test;
import java.util.Arrays;
import java.util.Date;
import java.util.GregorianCalendar;
public class TestDateProblem {
public static void main(String args[]) {
/*
* This is the date format that is mostly used. Logger shows this kind
* of date during Exception.
*/
String auditdate1 = "2011-12-27";
// Rarely sent this way.
String auditdate2 = "27-12-2011";
/*
* We don't send this way but I'm sure the problem occurs if the date goes this
* way. As far as the inputs are concerned, it doesn't go like this.
*/
String auditdate3 = "27-2011-12";
try {
System.out.println("Result1:" + getDateEndOfDay(auditdate1));
System.out.println("Result2:" + getDateEndOfDay(auditdate2));
// simulating problem?
System.out.println("Result3:" + getDateEndOfDay(auditdate3));
} catch (Exception e) {
System.out.println("auditdate1:" + auditdate1);
}
}
/*
* This getDateEndOfDay(.) method is called from many public methods and it
* may be possible that multiple threads are calling these static methods at
* the same time.
*/
public static Date getDateEndOfDay(String dateparam) throws Exception {
String separator = "/";
dateparam = dateparam.replace("-", separator);
String[] strP = dateparam.split(separator);
Integer year = getYear(strP);
Integer month = getMonth(strP);
Integer day = getDay(strP);
GregorianCalendar cal = new GregorianCalendar(year, month - 1, day, 23,
59, 00);
return cal.getTime();
}
private static Integer getYear(String[] dateComponents) throws Exception {
if (dateComponents.length != 3) {
return 1900;
}
System.out
.println("dateComponents::" + Arrays.toString(dateComponents));
Integer val1 = Integer
.valueOf(dateComponents[0].startsWith("0") ? dateComponents[0]
.substring(1) : dateComponents[0]);
Integer val2 = Integer
.valueOf(dateComponents[2].startsWith("0") ? dateComponents[2]
.substring(1) : dateComponents[2]);
if (val1 > 1900) {
return val1;
} else if (val2 > 1900) {
return val2;
} else {
// Original code throws exception instead of printing to console.
System.out.println("TestDateProblem: Problem with getYear method.");
throw new Exception();
}
}
private static Integer getDay(String[] dateComponents) {
if (dateComponents.length != 3) {
return -1;
}
Integer val1 = Integer
.valueOf(dateComponents[0].startsWith("0") ? dateComponents[1]
.substring(1) : dateComponents[0]);
Integer val2 = Integer
.valueOf(dateComponents[2].startsWith("0") ? dateComponents[1]
.substring(1) : dateComponents[2]);
if (val1 <= 31) {
return val1;
} else if (val2 <= 31) {
return val2;
} else {
System.out.println("TestDateProblem: Problem with getDay method.");
return 0;
}
}
private static Integer getMonth(String[] dateComponents) {
if (dateComponents.length != 3) {
return 0;
}
Integer val1 = Integer
.valueOf(dateComponents[1].startsWith("0") ? dateComponents[1]
.substring(1) : dateComponents[1]);
if (val1 <= 12 && val1 >= 1) {
return val1;
} else {
System.out
.println("TestDateProblem:: Problem with getMonth method");
return 0;
}
}
}
While the code is needlessly verbose, it is also reasonably clear. The problem you have is that its trying to work out whether the date is in yyyy/mm/dd format or dd/mm/yyyy format, however if you give it sometime like yy/mm/dd format it can't work out what it is and gives the error you see.
Stepping through the code with a debugger would confirm this.
I would read this comment again as it explains the problem
* We don't send this way but the problem occurs if the date goes this
* way.
You are giving it an invalid formatted date and it is rightly rejecting it because it doesn't know how to handle it.
There's no reason to believe that there are any thread-safety problems in this code. It has no static variables or other means by which non-local variable are manipulated. The only place where code which could even possibly be non-threadsafe is called is when you create a new GregorianCalendar object, but nothing in that documentation suggests that it wouldn't be threadsafe, so I think that's highly unlikely.
Also, isn't there already date-parsing stuff in Java? Why not just use java.text.SimpleDateFormat's parse method? Wouldn't that be much easier than all this?
You have a problem with auditdate3, not with auditdate1.
You pass 27-2011-12 as a date and try to extract a year. You check for a year at first and the last components of the date, but 27 and 12 are not a valid year. That's why you have an Exception. You should run your code in debugger.

How do I use parameters correctly in Java and why are they advantageous?

Here is the code:
class Time {
public static void printTime (int hour, int minute) {
System.out.print (hour) ;
System.out.print (":") ;
System.out.print (minute) ;
}
public static void main (String[] args) {
hour = 11 ;
minute = 30 ;
printTime () ;
}
}
Here is what terminal says when I try to compile it:
david-allenders-macbook-pro:~ davidallender$ Javac Time.java
Time.java:9: cannot find symbol
symbol : variable hour
location: class Time
hour = 11 ;
^
Time.java:10: cannot find symbol
symbol : variable minute
location: class Time
minute = 30 ;
^
Time.java:11: printTime(int,int) in Time cannot be applied to ()
printTime () ;
^
3 errors
david-allenders-macbook-pro:~ davidallender$
I'm in the process of learning so I don't really know what's going on. Right now I'm in the section in the book about parameters in/on/within/above/preposition (I'm not sure what the right preposition is) methods.
What does a parameter do?
Why is it useful?
What did I do wrong in the above code?
What did the error message mean?
Parameters give a method information it needs to do its job. For example, a function to find the square root of a number would have that number as a parameter.
You need to pass arguments to give the parameters values. So instead of trying to set minute and hour in the main method, you need to call
printTime(11, 30);
As a sort of meta-comment, this is the kind of thing you tend to learn pretty early - and while sites like this can help you with specific questions, you'd be better off reading a good entry level book about Java. If you're already reading a book but it didn't describe parameters clearly, you might want to think about getting another book :)
This should be better:
class Time {
public static void printTime (int hour, int minute) {
System.out.print (hour) ;
System.out.print (":") ;
System.out.print (minute) ;
}
public static void main (String[] args) {
int hour = 11 ;
int minute = 30 ;
Time.printTime (hour, minute) ;
}
}
Awful formatting. Do yourself a favor and think more carefully about how you format your code. It doesn't matter much for a small example like this, but you'll need it if your ambitions and programs grow.
I might write it like this:
package cruft;
import java.text.DecimalFormat;
import java.text.NumberFormat;
public class Time
{
private static final NumberFormat DEFAULT_FORMAT = new DecimalFormat("00");
private static final int DEFAULT_CAPACITY = 8;
private static final char DEFAULT_DELIMITER = ':';
private final int hour;
private final int minute;
private final int second;
public Time()
{
this(0, 0, 0);
}
public Time(int hour)
{
this(hour, 0, 0);
}
public Time(int hour, int minute)
{
this(hour, minute, 0);
}
public Time(int hour, int minute, int second)
{
this.hour = hour;
this.minute = minute;
this.second = second;
}
public String toString()
{
StringBuilder builder = new StringBuilder(DEFAULT_CAPACITY);
builder.append(DEFAULT_FORMAT.format(hour))
.append(DEFAULT_DELIMITER)
.append(DEFAULT_FORMAT.format(minute))
.append(DEFAULT_DELIMITER)
.append(DEFAULT_FORMAT.format(second));
return builder.toString();
}
public static void main(String[] args)
{
Time time = new Time(11, 5);
System.out.println(time);
}
}
Note: Consistent brace placement, methods indented, etc. That's what I mean.
I think one major thing you're doing wrong and should be pointed out specifically is that you're declaring parameters without defining their types. Java is known for it's static-as-a-frozen-rock type system which means that you always have to define the type of the variable, no matter what. To compare, in PHP you can do $number = 1; while in Java you cannot.
As a prototype, each variable/parameter declaration follows the [type] [name] = [possible default value]; pattern, for example int number = 1;. Valid types are primitives (int, double, byte, char etc.) and of course objects such as String or Calendar or whatever class you might be using.
The same staticness applies to calling methods, you need to explicitly provide each method with exact amount of parameters with correct types to be able to call them. Java does automatically cast down or up some primitive values such as int to long where applicable, but generally in Java you're going to use actual objects and those are only downcasted if applicable. You can't provide default values for methods' parameters automatically in the same way as C/C++/PHP, that is you can't do this
public void callMe(int number = 911) { ... }
but you have to do this
public void callMe() { callMe(911); }
public void callMe(int number) { ... }
to get the same effect.
Naturally there's always exceptions to even the most fundamental rules such as difference between static and dynamic typing, satisfying method with right amount of parameters and default values but you can forget those for the time being and concentrate on the basics first. Hopefully this helps you!

Categories