How do I put months in each array? - java

I'm making a program for expense statistics over a month; however, I don't know what I should do in the for loop in order to make it initialize each MonthlyExpensePeriods with the corresponding name of that month in the correct order?
for(int i = 0; i < 12; i++){
monthlyExpensePeriods[i] = new MonthlyExpensePeriods(month's name);
}

You could use DateFormatSymbols.getMonths():
String[] monthNames = new DateFormatSymbols().getMonths();
for(int i = 0; i < 12; i++){
monthlyExpensePeriods[i] = new MonthlyExpensePeriods(monthNames[i]);
}

tl;dr
Use Month enum objects rather than mere text of name of month.
for(int i = 1; i <= 12; i++){
monthlyExpensePeriods[i] = new MonthlyExpensePeriod( Month.of( i ) );
}
Use smart objects, not dumb strings
Using strings for special values, such as tracking each month of the year, is fragile and error-prone.
Month
Instead, use objects.
In Java 8 and later, we have the Month enum class built-in. This enum predefines a dozen objects, one for each month of the year, each assigned to a named constant.
Your class MonthlyExpensePeriod should hold a member variable of type Month.
public class MonthlyExpensePeriod {
// Member fields
public Month month ;
…
// Constructor
public MonthlyExpensePeriod( final Month monthArg ) {
this.month = monthArg ;
…
}
}
To use that class and its constructor, pass one of the named constants.
new MonthlyExpensePeriod ( Month.MARCH )
You can retrieve one of the Month objects by month number. Notice the sane numbering, 1-12 for January-December.
Month month = Month.of( 3 ) ; // Month.MARCH
So your example code would look like the following. Change your for loop to count 1-12.
for(int i = 1; i <= 12; i++){
monthlyExpensePeriods[i] = new MonthlyExpensePeriod( Month.of( i ) );
}
Collections
You may want to use Java Collections rather than mere arrays.
List< MonthlyExpensePeriod > periods = new ArrayList<>( 12 ) ;
for(int i = 1; i <= 12; i++){
MonthlyExpensePeriod period = new MonthlyExpensePeriod( Month.of( i ) ) ;
periods.add( period );
}
Streams
I suppose we could get fancy and use streams. But in this case I do not see any added-value.
Calling Month.values() returns an array of all the objects defined on the enum, in the order in which they were defined. From that, we can generate a stream by calling the utility class method Arrays.stream.
List < MonthlyExpensePeriod > periods =
Arrays.stream( Month.values() )
.map( month -> new MonthlyExpensePeriod( month ) )
.collect( Collectors.toList() )
;
Or as a single-line of code.
List < MonthlyExpensePeriod > periods = Arrays.stream( Month.values() ).map( month -> new MonthlyExpensePeriod( month ) ).collect( Collectors.toList() );
You might want to make an unmodifiable copy of your list.
List < MonthlyExpensePeriod > periodsUnmod = List.copyOf( periods );
Or make the original list unmodifiable, by calling Collectors.toUnmodifiableList(), as discussed here.
List < MonthlyExpensePeriod > periods =
Arrays
.stream( Month.values() )
.map( month -> new MonthlyExpensePeriod( month ) )
.collect( Collectors.toUnmodifiableList() )
;
Generating display text
You may want to display the name of the month.
Calling Month::toString generates text of the name in English in all caps. Instead you can automatically localize.
To localize, pass a TextStyle object to signal how long or abbreviated you want the name. Notice that TextStyle offers STANDALONE variations used in some languages (not English) where the month name appears outside the context of a date.
And pass a Locale to determine the human language and cultural norms to use in localizing.
Locale locale = Locale.CANADA_FRENCH ; // Or Locale.US and so on.
String output = Month.MARCH.getDisplayName( TextStyle.FULL , locale ) ;

Related

Creating an order-slot system with 2 array lists

I need to write a daymanagerr that assigns time slots for orders in a restaurant.
That's the daymanager:
public DayManager (LocalDate date, int numberOfTimeSlots, int capacityPerSlot) {
this.date = date;
this.capacityPerSlot = capacityPerSlot;
this.numberOfTimeSlots = numberOfTimeSlots;
For each day I can choose the number of available slots and the capacity per slot (so if I choose 3 slots and a capacity of 3 per slot, that's 9 slots in total).
Every customer can state their preferred time slot (here: 0, 1 or 2) with their order.
Here's my class for adding orders:
public Optional<Integer> addOrder(Order order, int preferredSlot) {
int givenSlot = 0, count = 1;
List<Integer> slots = new ArrayList<Integer>();
List<Integer> slotsPerSlot = new ArrayList<Integer>();
if ((slots.size() * slotsPerSlot.size()) <= (numberOfTimeSlots * capacityPerSlot)) {
if (slots.contains(preferredSlot) == false) {
givenSlot = preferredSlot;
slots.add(preferredSlot);
slotsPerSlot.add(count);
count++;
} else if (slotsPerSlot.size() <= capacityPerSlot) {
givenSlot = preferredSlot;
slots.add(preferredSlot);
slotsPerSlot.add(slotsPerSlot.size() + 1);
} else {
givenSlot = slots.get(slots.lastIndexOf(count));
}
return Optional.of(givenSlot);
}
return Optional.empty();
}
What I need help with:
With every new order I get, I need to check if there is still capacity left in that customers preferred slot. If there is capacity left, I assign that slot to him. If there is no capacity left in that slot, I assign the slot with the next lowest index (and available capacity). If there is no capacity left for that day, I simply return nothing.
I just can't figure out how to create a slotsPerSlot list for each slot and additionally I don't really know, how I could get the next lowest slot number.
Multimap
You could use a multimap. A Map is a pairing of key that leads to a value. In a multimap, the value is actually a collection of values rather than a single value.
Imagine, for example, a hierarchy of three time slots where the first and last contain an empty list (no orders yet), while the middle time slot has a list of a single order.
2022-01-23T13:00-07:00[America/Edmonton]
[]
2022-01-23T14:00-07:00[America/Edmonton]
[Order[id=2d8e5cc2-26ac-474d-a081-2c71207fd6c5, customerName=Basil]]
2022-01-23T15:00-07:00[America/Edmonton]
[]
(Minor detail: The 2d8e5cc2-26ac-474d-a081-2c71207fd6c5 text is a hexadecimal string representation of a 128-bit UUID value used to identify that particular order.)
Example code
Here is some example code. This code is incomplete, but will get you going in the right direction.
First, define our Order class. We will make it a record, using the new feature in Java 16. You could just as well define a conventional class, but a record is so much briefer. The compiler implicitly creates the constructor, getters, equals & hashCode, and toString.
package work.basil.example.orders;
import java.util.UUID;
public record Order(UUID id , String customerName)
{
}
Define the DayManager class.
The constructor is the place to set up your data structure for tracking orders. You were doing that work inside your addOrder method which makes no sense.
The goal of the constructor is to populate a NavigableMap, a Map that maintains its keys it a sorted order. We use TreeMap as the concrete implementation of the NavigableMap interface.
The keys to our map are ZonedDateTime, a date with time-of-day within the context of a time zone. Each ZonedDateTime object is the start of each time slot. I use this approach rather than your mere integer number to identify each slot.
The values of our map are a list of Order objects. As we add orders to our tracking system, they land in one of these lists. Each list is tied to a ZonedDateTime object as the time slot in our map. The problem with using a List is that the class is meant to be a resizable collection. So our code here manages the size limits, checking the current size to get a count of how many orders are already present in the list. We compare that count to our capacity-per-time-slot number we keep as a member field on DayManager class.
If we are under capacity, we add our order to the list, and return an Optional containing the ZonedDateTime to identify the time slot.
If we are at capacity, we need to move on to the next time slot — this I leave as an exercise for the reader.
Hint: We have a ZonedDateTime in hand, the current key used to access our map. So if we add the Duration stored as a member field, we will obtain the next key in our map. Use that key to get the next list of orders. Lather, rinse, repeat, until moving past the last time slot of the day.
By the way, in real work, I would look to a third-party library such as Eclipse Collections or Google Guava for a fixed-size list class. Better to rely on code that is already written and tested than rely on our size-checking code here.
We pre-populate our map with time slots and empty lists in the constructor. So we have a data structure in place when we begin adding orders.
The addOrder method looks for the requested time slot as the key in the map. Doing a get on the map returns a List of orders for us to inspect.
package work.basil.example.orders;
import java.time.*;
import java.util.*;
public class DayManager
{
// Member fields.
final ZoneId zoneId;
final LocalDate workDate;
final LocalTime startTime;
final Duration timeSlice;
final int numberOfTimeSlots, capacityPerTimeSlot;
private final NavigableMap < ZonedDateTime, List < Order > > ordersPerTimeSlot;
// Constructor
public DayManager ( final ZoneId zoneId , final LocalDate localDate , final LocalTime startTime , final Duration timeSlice , final int numberOfTimeSlots , final int capacityPerSlot )
{
this.zoneId = zoneId;
this.workDate = localDate;
this.startTime = startTime;
this.timeSlice = timeSlice;
this.numberOfTimeSlots = numberOfTimeSlots;
this.capacityPerTimeSlot = capacityPerSlot;
this.ordersPerTimeSlot = new TreeMap <>();
this.populateMap();
}
// Subroutine.
private void populateMap ( )
{
ZonedDateTime start = ZonedDateTime.of( this.workDate , this.startTime , this.zoneId );
for ( int i = 0 ; i < this.numberOfTimeSlots ; i++ )
{
Duration d = this.timeSlice.multipliedBy( i );
ZonedDateTime zdt = start.plus( d );
List < Order > list = new ArrayList <>( this.capacityPerTimeSlot );
this.ordersPerTimeSlot.put( zdt , list );
}
System.out.println( "this.ordersPerTimeSlot = " + this.ordersPerTimeSlot );
}
// Business logic.
public Optional < ZonedDateTime > addOrder ( final Order order , final ZonedDateTime zdt )
{
List < Order > orders = this.ordersPerTimeSlot.get( zdt );
if ( Objects.isNull( orders ) ) { return Optional.empty(); }
if ( orders.size() > this.capacityPerTimeSlot )
{
String msg = "ERROR - Capacity per time slot exceeded. ";
System.out.println( msg );
throw new IllegalStateException( msg );
} else if ( orders.size() == this.capacityPerTimeSlot )
{
String msg = "INFO - This time slot filled.";
System.out.println( msg );
throw new IllegalStateException( msg );
} else if ( orders.size() < this.capacityPerTimeSlot )
{
// Room in this time slot to place order.
orders.add( order );
return Optional.of( zdt );
} else
{
String msg = "ERROR - Should never reach this point. Error in IF-THEN logic of adding orders.";
System.out.println( msg );
throw new IllegalStateException( msg );
}
}
// Debugging
public String dumpOrders ( )
{
return this.ordersPerTimeSlot.toString();
}
}
Here is an App class for exercising our DayManager & Order classes.
package work.basil.example.orders;
import java.time.*;
import java.util.Optional;
import java.util.UUID;
public class App
{
public static void main ( String[] args )
{
ZoneId z = ZoneId.of( "America/Edmonton" );
LocalDate ld = LocalDate.of( 2022 , Month.JANUARY , 23 );
DayManager dm = new DayManager( z , ld , LocalTime.of( 13 , 0 ) , Duration.ofHours( 1 ) , 3 , 3 );
Order order = new Order( UUID.fromString( "2d8e5cc2-26ac-474d-a081-2c71207fd6c5" ) , "Basil" );
Optional < ZonedDateTime > optionalTimeSlot = dm.addOrder( order , ZonedDateTime.of( ld , LocalTime.of( 14 , 0 ) , z ) );
System.out.println( "order = " + order );
System.out.println( "optionalTimeSlot.toString() = " + optionalTimeSlot );
System.out.println( dm.dumpOrders() );
}
}
When run.
this.ordersPerTimeSlot = {2022-01-23T13:00-07:00[America/Edmonton]=[], 2022-01-23T14:00-07:00[America/Edmonton]=[], 2022-01-23T15:00-07:00[America/Edmonton]=[]}
order = Order[id=2d8e5cc2-26ac-474d-a081-2c71207fd6c5, customerName=Basil]
optionalTimeSlot.toString() = Optional[2022-01-23T14:00-07:00[America/Edmonton]]
{2022-01-23T13:00-07:00[America/Edmonton]=[], 2022-01-23T14:00-07:00[America/Edmonton]=[Order[id=2d8e5cc2-26ac-474d-a081-2c71207fd6c5, customerName=Basil]], 2022-01-23T15:00-07:00[America/Edmonton]=[]}

I'm confused on getters and returns in classes?

I've been teaching myself coding, and getters and return values, and how to call upon them in the main program. To give it a go, I tried to write a program to calculate the cost of long distance calls, but it crashes right when I run it, and I know it has something to do with the class.
Fair warning, my time is a bit weird for calculating AM/PM but I did my best.
I think it has to be something with calling upon the calculations in my main code-- specifically the String weekday = call1.calculateweekday(); and int time = call1.calculatetime(); , but I'm very new to programming and I am very much just starting out and learning these terms and uses, so I've no idea what. I just know, when i move these two lines around my main program, it breaks at that point.
package practice;
import java.util.Scanner;
class Call {
String weekdayinput;
String weekday;
int hour;
String ampm;
int time;
int calculatetime() {
if (ampm.equals("pm") || ampm.equals("PM") || ampm.equals("Pm")) {
time = hour + 1200;
} else if (ampm.equals("am") || ampm.equals("AM") || ampm.equals("Am")) {
time = hour;
}
else {
System.out.println("You entered something either time or AM/PM incorrectly.");
}
return time;
}
String calculateweekday() {
if (weekdayinput.equals("mo") || weekdayinput.equals("Mo") || weekdayinput.equals("MO")) {
weekday = "Monday";
}
else if (weekdayinput.equals("tu") || weekdayinput.equals("Tu") || weekdayinput.equals("TU")) {
weekday = "Tuesday";
}
else if (weekdayinput.equals("we") || weekdayinput.equals("We") || weekdayinput.equals("WE")) {
weekday = "Wednesday";
}
else if (weekdayinput.equals("th") || weekdayinput.equals("Th") || weekdayinput.equals("TH")) {
weekday = "Thursday";
}
else if (weekdayinput.equals("fr") || weekdayinput.equals("Fr") || weekdayinput.equals("FR")) {
weekday = "Friday";
}
else if (weekdayinput.equals("sa") || weekdayinput.equals("Sa") || weekdayinput.equals("SA")) {
weekday = "Saturday";
}
else if (weekdayinput.equals("su") || weekdayinput.equals("Su") || weekdayinput.equals("SU")) {
weekday = "Sunday";
}
else {
System.out.println("You entered your weekday incorrectly.");
}
return weekday;
}
}
public class GettersandREturns {
public static void main(String args[]) {
Scanner input = new Scanner(System.in);
Call call1 = new Call();
String weekday = call1.calculateweekday();
int time = call1.calculatetime();
System.out.println("To calculate the cost per minute of your long-distance call, we'll need some information.");
System.out.println(
"What hour are you planning on making the call. Minutes aren't necessary. Please only enter the hour number. (ex. 8)");
call1.hour = input.nextInt();
input.hasNextLine();
System.out.println("Is the call taking place AM or PM?");
call1.ampm = input.nextLine();
input.hasNextLine();
System.out.println("And what day of the week is that? Please enter weekday with only first two letters. (ex. Fr");
call1.weekdayinput = input.nextLine();
if (time >= 8 && time <= 11 && !weekday.equals("Saturday") && !weekday.equals("Sunday")
|| time >= 1212 && time <= 1206 && !weekday.equals("Saturday") && !weekday.equals("Sunday"))
{
System.out.println("Your call will charge $4.50 a minute.");
}
else if (time == 12 && !weekday.equals("Saturday") && !weekday.equals("Sunday")
|| time >= 1 && time < 8 && !weekday.equals("Saturday") && !weekday.equals("Sunday")
|| time > 1206 && time <= 1211 && !weekday.equals("Saturday") && !weekday.equals("Sunday")) {
System.out.println("Your call will charge $4.00 a minute.");
}
else if (weekday.equals("Saturday") || weekday.equals("Sunday")){
System.out.println("Your call will charge $2.25 a minute.");
}
else {
System.out.println("You must have entered something wrong!");
}
}
}
So the idea was any call started between 8:00 Am and 6:00 PM, Monday through Friday, is billed at a rate of 4.50 per minute. Any call starting before 8:00 AM or after 6:00 PM, Monday through Friday, is billed at a rate
of 4.00 per minute. Finally, any call started on a Saturday or Sunday is charged at a rate of 2.25 per minute.
But when i run this program I get Exception in thread "main" java.lang.NullPointerException
at practice.Call.calculateweekday(GettersandREturns.java:32)
at practice.GettersandREturns.main(GettersandREturns.java:82)
Any help would be greatly appreciated. Learning is hard.
In your main function you are creating a new call and calling the functions of the call.
Call call1 = new Call();
String weekday = call1.calculateweekday();
int time = call1.calculatetime();
And at this Points you get the error, if you look at the Call class which got the following variables
String weekdayinput;
String weekday;
int hour;
String ampm;
int time;
You see that These variables aren't initialized at the beginning, for int the Default value is 0 and for a String the Defaultvalue is null (you will Encounter nullpointerexceptions sometimes when you are programming). Having a value of null not forbidden as Long as you dont try to Access this variable and that is what your functions do.
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.String.equals(java.lang.Object)' on a null object reference
will be the error which
if (ampm.equals("pm") || ampm.equals("PM") || ampm.equals("Pm"))
will throw, as your ampm or any other String you are trying to Access is null at this Point and you are trying to compare the null String with a string.
Make sure, that you initialize your Strings before you compare them with anything, for example with
String weekdayinput = "mo";
String weekday "mo";
int hour;
String ampm "am";
int time;
And you should call the functions for weekday and time after you asked for the Input.
Scanner input = new Scanner(System.in);
Call call1 = new Call();
System.out.println("To calculate the cost per minute of your long-distance call, we'll need some information.");
System.out.println(
"What hour are you planning on making the call. Minutes aren't necessary. Please only enter the hour number. (ex. 8)");
call1.hour = input.nextInt();
input.hasNextLine();
System.out.println("Is the call taking place AM or PM?");
call1.ampm = input.nextLine();
input.hasNextLine();
System.out.println("And what day of the week is that? Please enter weekday with only first two letters. (ex. Fr");
call1.weekdayinput = input.nextLine();
String weekday = call1.calculateweekday();
int time = call1.calculatetime();
And as a sidenote: You should read About switches which can replace this many if Statements.
Further thoughts
The Answer by Wuttke is correct and should be accepted. Here's a few more extraneous thoughts.
Generally best to keep each class in its own .java file.
Be careful with naming. Being descriptive and specific makes your code much easier to read, review, and revise. So call your Scanner object something like scanner rather than input.
You can shorten some logic by converting text inputs to all uppercase or lowercase.
Your code time > 1206 && time <= 1211 left me puzzled. I do not understand your intent.
Separate user-interface from business logic. The rules for days and times for various charges should be segregated to their own class. That makes for one place with very simple short code to read and edit when your business rules change. And business rules always change, eventually.
Do all the data-entry validation in your user-interface code, keeping that separated from your business logic code. Pass already-validated data to the business logic (here, the code that determines pricing). The idea is to focus on a single responsibility. The business logic code should only be burdened with the job of knowing the day & time pricing scheme, not interacting with the user. Likewise, the UI code should not know about the nitty-gritty details of call-costing, but should know only enough to validate data-entry.
Instead of the series of if statements, use switch as shown in the Oracle Tutorial.
Use smart objects rather than dumb strings or mere integers, whenever possible. Java offers the DayOfWeek enum, so use those seven pre-defined objects rather than clumsy strings. Likewise, we have a LocalTime class for time-of-day without date and without time zone.
Java has strong features for localizing. So no need to hard-code things like dollar sign and name of day-of-week.
Resources such as a Scanner should be closed when you are done using them. The try-with-resources syntax automates this chore.
Example code
Here is some example code. Not meant for production, not tested. But should prove interesting to someone learning Java.
In real work I would:
Do more error-checking, like checking for the scanner being closed.
Pull out each of the parsing sections (hour, AM/PM, and day-of-week) into subroutines (named private methods).
Replace the conventional switch statement to the new simplified switch statement being previewed in Java 12 & Java 13.
Give the user an exit option on every prompt, like q to quit.
Use unit testing to verify logic.
First, the business logic portion.
package work.basil.example;
import java.math.BigDecimal;
import java.time.DayOfWeek;
import java.time.LocalTime;
import java.util.EnumSet;
import java.util.Objects;
import java.util.Set;
public class CallCostEstimator
{
private Set < DayOfWeek > weekdays = EnumSet.of ( DayOfWeek.MONDAY , DayOfWeek.TUESDAY , DayOfWeek.WEDNESDAY , DayOfWeek.THURSDAY , DayOfWeek.FRIDAY );
LocalTime daytimeStart = LocalTime.of ( 8 , 0 );
LocalTime daytimeStop = LocalTime.of ( 18 , 0 );
BigDecimal weekday_day_rate = new BigDecimal ( "4.5" );
BigDecimal weekday_night_rate = new BigDecimal ( "4.0" );
BigDecimal weekend_rate = new BigDecimal ( "2.25" );
public BigDecimal estimate ( LocalTime localTime , DayOfWeek dayOfWeek )
{
Objects.requireNonNull ( localTime );
Objects.requireNonNull ( dayOfWeek );
boolean isWeekday = ( weekdays.contains ( dayOfWeek ) );
boolean isDaytimeHours = ( ! localTime.isBefore ( this.daytimeStart ) ) && ( localTime.isBefore ( this.daytimeStop ) );
// Determine price slot
BigDecimal result = null;
if ( ! isWeekday )
{
result = this.weekend_rate; // In other cases we would make a copy before returning an object stored within this class. But `BigDecimal` is immutable, so not necessary.
} else
{ // Else is weekday.
if ( isDaytimeHours )
{
result = this.weekday_day_rate;
} else
{
result = this.weekday_night_rate;
}
}
if ( Objects.isNull ( result ) ) // Should not be possible if our cascade of `if` statements is complete and correct. Defensive programming requires that we check.
{
throw new IllegalStateException ( "Failed to find a price slot." );
}
return result;
}
}
And the user-interface portion.
package work.basil.example;
import java.math.BigDecimal;
import java.text.NumberFormat;
import java.time.DayOfWeek;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.time.format.TextStyle;
import java.util.*;
public class CallCostEstimateConsole
{
public static void main ( String[] args )
{
CallCostEstimateConsole app = new CallCostEstimateConsole ();
app.engageUser ();
}
public void engageUser ( )
{
// Use try-with-resources syntax to auto-close the scanner.
try (
Scanner scanner = new Scanner ( System.in ) ;
)
{
System.out.println ( "To calculate the cost per minute of your long-distance call, we'll need some information." );
Integer hour = null;
while ( Objects.isNull ( hour ) )
{
System.out.println ( "What hour are you planning on making the call? Minutes aren't necessary. Please only enter the hour number, 1-12 for 12-hour clock. (ex. 8)" );
try
{
int input = scanner.nextInt ();
if ( ( input < 1 ) || ( input > 12 ) )
{
System.out.println ( "Hour must be from 1 to 12." );
} else
{
hour = input;
}
} catch ( InputMismatchException e )
{
System.out.println ( "Error: Enter a digits only, for a number from 1 to 12. " );
}
}
String amPm = null;
while ( Objects.isNull ( amPm ) )
{
System.out.println ( "Is the call taking place AM or PM? (type either AM or PM, or am or pm)" );
String input = scanner.next ();
input = input.toUpperCase ();
if ( input.equals ( "AM" ) || ( input.equals ( "PM" ) ) )
{
amPm = input;
} else
{
System.out.println ( "You typed something other than AM or PM." );
continue;
}
// Tweak inputs for 12-hour to 24-hour conversion.
if ( amPm.equals ( "AM" ) && ( hour == 12 ) )
{
hour = 0;
}
}
// If 1 PM through 11 PM, add 12 hours for 24-hour time.
hour = ( amPm.equals ( "PM" ) & ( hour < 12 ) ) ? ( hour + 12 ) : hour; // Ternary statement. A compact alternative to an `if` statement.
LocalTime localTime = LocalTime.of ( hour , 0 );
DayOfWeek dayOfWeek = null;
while ( Objects.isNull ( dayOfWeek ) )
{
System.out.println ( "And what day of the week is that? Please enter weekday with only first two letters. (ex. Fr)" );
try
{
String input = scanner.next ().toLowerCase ();
if ( input.isEmpty () )
{
System.out.println ( "You did not type any characters. " );
continue; // Break-out to continue on to the next loop.
}
// Parsing logic.
switch ( input )
{
case "mo":
dayOfWeek = DayOfWeek.MONDAY;
break;
case "tu":
dayOfWeek = DayOfWeek.TUESDAY;
break;
case "we":
dayOfWeek = DayOfWeek.WEDNESDAY;
break;
case "th":
dayOfWeek = DayOfWeek.THURSDAY;
break;
case "fr":
dayOfWeek = DayOfWeek.FRIDAY;
break;
case "sa":
dayOfWeek = DayOfWeek.SATURDAY;
break;
case "su":
dayOfWeek = DayOfWeek.SUNDAY;
break;
default:
String message = "You did not type a 2-letter day-of-week code as expected. (Mo, Tu, We, Th, Fr, Sa, Su)";
throw new IllegalStateException ( message );
}
} catch ( InputMismatchException e )
{
System.out.println ( "Error: Enter a digits only, for a number from 1 to 12. " );
}
}
// Calculate result.
CallCostEstimator estimator = new CallCostEstimator ();
BigDecimal estimate = estimator.estimate ( localTime , dayOfWeek );
// Report result.
String output = NumberFormat.getInstance ( Locale.US ).getCurrencyInstance ().format ( estimate );
DateTimeFormatter f = DateTimeFormatter.ofLocalizedTime ( FormatStyle.SHORT ).withLocale ( Locale.US );
String dow = dayOfWeek.getDisplayName ( TextStyle.FULL , Locale.US );
String message = "Your call at " + localTime.format ( f ) + " on " + dow + " will cost per minute: " + output;
System.out.println ( message );
}
}
}
Example run.
To calculate the cost per minute of your long-distance call, we'll need some information.
What hour are you planning on making the call? Minutes aren't necessary. Please only enter the hour number, 1-12 for 12-hour clock. (ex. 8)
1
Is the call taking place AM or PM? (type either AM or PM, or am or pm)
am
And what day of the week is that? Please enter weekday with only first two letters. (ex. Fr)
mo
Your call at 1:00 AM on Monday will cost per minute: $4.00

Interval between int months in Java

I have two int variables monthFrom and monthUntil which represent an interval. I want to write a method which would find if any winter month overlaps this interval. For example, if monthFrom == 3, monthUntil == 5, the method would return false, if monthFrom == 2, monthUntil == 8 - true, if monthFrom == 10, monthUntil= = 3 - true, and so on.
Being a beginner at Java I'm not sure how do I do this. Any help?
Joe my code helps you for your problem.
I am using HashMap Collection to store the values of months as it contains fixed number of months corresponding to values i.e name of month.
Find my code below
public class FindWinterMonth {
HashMap<Integer, String> months = null;
public FindWinterMonth() {
months = new HashMap<Integer, String>();
months.put(10, "October");
months.put(11, "November");
months.put(12, "December");
months.put(1, "January");
months.put(2, "Febuary");
}
public boolean isWinterMonth(int monthFrom, int monthUntil){
boolean isPresent = false;
for(int i = monthFrom; i <= monthUntil; i++){
if(months.containsKey(i)){
isPresent = true;
}
}
return isPresent;
}
public static void main(String[] args) {
FindWinterMonth fm = new FindWinterMonth();
boolean isWinter = fm.isWinterMonth(4,9);
System.out.println(isWinter);
}
}
I am sure it helps you and if anyone have good and efficient solutions share with us.
Thanks!
You can use the code like this:
if (monthFrom <= monthUntil && monthUntil != 12 && monthFrom >= 3)
return false;
else
return true;
Or you can simplify this code like this:
return !(monthFrom <= monthUntil && monthUntil != 12 && monthFrom >= 3);
Given the provided rules the given code should produce the desired output:
public static void main(String[] args){
isWinter(3,5);
isWinter(2,8);
isWinter(10,3);
}
public static void isWinter(int monthFrom, int monthUntil) {
if(monthFrom <= monthUntil && monthFrom < 3 ||
monthFrom > monthUntil && monthUntil <= 3) {
System.out.println("Winter time");
} else {
System.out.println("Not winter time");
}
}
O/P
Not winter time
Winter time
Winter time
The check applies the rules that it´s winter when monthUntil <= 3 when monthFrom > monthUntil or monthFrom < 3 when monthFrom < monthUntil.
As there was no clear definition i assumed the rules from isWinter(3,5); having to return false and isWinter(10,3); having to return true.
I understand you are a Java beginner and you want to fiddle with the basics for now. That is a good thing, and I encourage you to proceed.
Nevertheless, you should avoid to mess with time-related code on basic level in your more advanced programs. Time is a delicate topic and several generations of programmers have spent hours and weeks to make it manageable in Java. If you already use Java 8, there is a sophisticated date-time API in package java.time.
In addition, you might want to check Interval from project ThreeTen-Extra. It provides methods for calculating overlaps between intervals.
Use Objects, not numbers
Better to work with objects than mere integer numbers. This makes your code more self-documenting, ensures valid values, and provides type-safety.
Month
For months, Java provides the Month class. As an Enum, the class pre-defines a dozen objects, one for every month, number 1-12 for January-December.
EnumSet
An EnumSet is a special implementation of Set optimized for holding enum objects. EnumSet objects happen to be extremely fast to execute and very small in memory. Use that to define “Winter” as a set of months.
Set<Month> winter = EnumSet.of ( Month.DECEMBER , Month.JANUARY , Month.FEBRUARY );
As for your range of months, define that too as a EnumSet. Instantiating is easy as the class provides the range method.
//Set<Month> range = EnumSet.range ( Month.of ( 3 ) , Month.of ( 5 ) );
Set<Month> range = EnumSet.range ( Month.of ( 2 ) , Month.of ( 8 ) );
Compare sets
Next we need to know if any of the elements in the range set are in the winter set. Unfortunately, there is no containsAny kind of method in the Set interface. We can get that behavior with a bit more code, creating a copy of winter, then calling removeAll to remove any matching elements contained in range, and finally comparing to the original winter.
Set<Month> winterMonthsNotInRange = EnumSet.copyOf ( winter );
winterMonthsNotInRange.removeAll ( range );
Boolean rangeContainsWinterMonths = ( ! winter.equals ( winterMonthsNotInRange ) ); // If different, the range contained one or more winter months.
Alternatively, create a set of the winter months that were in common and ask if that set is non-empty.
Set<Month> winterMonthsInRange = EnumSet.copyOf ( winter );
winterMonthsInRange.removeAll ( winterMonthsNotInRange );
Boolean rangeContainsWinterMonths = ( winterMonthsInRange.size() > 0 );
Dump to console.
System.out.println ( "winter: " + winter );
System.out.println ( "range: " + range );
System.out.println ( "winterMonthsNotInRange: " + winterMonthsNotInRange );
System.out.println ( "rangeContainsWinterMonths: " + rangeContainsWinterMonths );
System.out.println ( "winterMonthsInRange: " + winterMonthsInRange );
winter: [JANUARY, FEBRUARY, DECEMBER]
range: [FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST]
winterMonthsNotInRange: [JANUARY, DECEMBER]
rangeContainsWinterMonths: true
winterMonthsInRange: [FEBRUARY]
See live code in IdeOne.com.
About Month
Remember, these are not mere strings in play. The Month objects are real OOP objects with data and methods combined. The all-uppercase names you see in the output above are String objects generated by the Enum::toString method. You can alternatively generate strings automatically localized in other languages via Month::getDisplayName method, such as janvier in French for January.
If unfamiliar with the Java enum facility, study the Oracle Tutorial. They are much more powerful than enums in other languages, yet very easy to use and very handy.
Remember that you can be passing these Month objects and EnumSet/Set objects around your code. Minimize where you use the mere integers to represent months.
Tips:
You may also find the YearMonth and MonthDay classes useful.
Be aware of standard ISO 8601 formatted strings when serializing to text.

Java : given a list of object that has range of dates find two objects whose end month is closest to current date month

List of dates are as below (The list can be in any order):
3-Jan to 31-Mar, 2-Apr to 30-Jun, 1-Jul to 30-Sep, 4-Oct to 31-Dec
Current Date is: 19-Feb
Can someone please help me with the logic?
My approach is:
if(the given date should be greater than start date and less than end date){//this gives current quarter}else if(difference of the month of current date from the end date of each object should be less than or equal to 5)
i am hard coding the condition less than 5, which may break if in future the range of date will be of 4 months
Second approach is:
we can sort the list in ascending order and can get the current quarter index by comparing with current date and the next quarter will be of next index. But the complexity will be more.
I tried below code, but it gives only current quarter date. I am not able to get next quarter considering there would be only 3 objects and current date month is feb.
public static List getCurrentQtrOffr(List detail,Date currentDate) throws ParseException{
int currentQuarter = 9999, diff1;
int nextquarter = 9999, diff2;
Detail detail1;
Detail detail2;
Detail detail3 = null;
Detail detail4 = null;
Iterator<Detail> iterator = detail.iterator();
List<Detail> list = new ArrayList<Detail>();
while(iterator.hasNext()){
detail1 = iterator.next();
diff1 = getDiff(currentDate,detail1.startTime());
if(diff1>0){
if(iterator.hasNext()){
detail2 = iterator.next();
}else{
detail2 = null;
}
if(detail2 != null){
diff2 = getDiff(currentDate,detail2.startTime());
if(diff1 < diff2 ){
if(currentQuarter > diff1){
nextquarter = currentQuarter;
currentQuarter = diff1;
//how to assign detail3 before updating it with next minimum value, as if there will be only 3 object and flow comes in this if block then detail4 will be null
detail4=detail3;
detail3=detail1;
}else if(nextquarter > diff1){
nextquarter = diff1;
detail4=detail1;
}
}else{
if(currentQuarter > diff2){
nextquarter = currentQuarter;
currentQuarter = diff2;
detail4=detail3;
detail3=detail1;
}else if(nextquarter > diff2){
nextquarter = diff2;
detail4=detail1;
}
}
}else{
if(currentQuarter > diff1){
nextquarter = currentQuarter;
currentQuarter = diff1;
detail4=detail3;
detail3=detail1;
}else if(nextquarter > diff1){
nextquarter = diff1;
detail4=detail1;
}
}
}else{
System.out.println("skipped "+diff1);
}
}
list.add(detail3);
list.add(detail4);
return list;
}
If the periods are mutually exclusive (not overlapping) the you simply check for the first occurrence where:
The target is equal to or later than the start, and…
The target is before the stop.
This logic follows the Half-Open approach commonly used in date-time work where the beginning is inclusive while the ending is exclusive.
A shorter way of saying "the target is equal to or later than the start" is "not before start". The exclamation mark ! means not in Java syntax.
Boolean periodContainsTarget = ( ! target.isBefore( start ) ) && target.isBefore( stop ) ;
The above logic would be used with LocalDate if you meant date with a year. If you literally meant a month and day without a year, use the MonthDay class. The logic works for both.
Use Period class to represent the span of time between a pair of LocalDate objects. See Tutorial.
You might also find useful the Interval class in the ThreeTen-Extra project that supplements java.time.

Java Joda-Time , assign LocalDate to Month and Year

I have never used Joda-Time before but I have ArrayList which contains objects with LocalDate and count. So I have count for each day in ArrayList and each day is only once in ArrayList.
I need to calculate counts for each month of year, which is in list.
My data:
E.g.:
dd.MM.yyyy
17.01.1996 (count 2)
18.01.1996 (count 3)
19.02.1996 (count 4)
19.03.1996 (count 1)
18.05.1997 (count 3)
Now I want outpur like this:
MM.yyyy
01.1996 -> 2 (17.1.1996) + 3 (18.1.1996) = 5
02.1996 -> 4 (19.2.1996) = 4
03.1996 -> 1 (19.3.1996) = 1
05.1997 -> 3 (18.5.1997) = 3
Simply I need to get count for each month, but I do not know what would be best way to achieve this.
Data class:
private class Info{
int count;
LocalDate day;
}
And result I would put in some class which contains Month and Year date + count.
In Joda-Time, there is class that represents Year + Month information, named YearMonth.
What you need to do is mostly construct a Map<YearMonth, int> to store the count of each YearMonth, by looping through your original List which contains LocalDate and count, and update the map accordingly.
Conversion from LocalDate to YearMonth should be straight forward: YearMonth yearMonth = new YearMonth(someLocalDate); should work
in pseudo-code, it looks like:
List<Info> dateCounts = ...;
Map<YearMonth, Integer> monthCounts = new TreeMap<>();
for (Info info : dateCounts) {
YearMonth yearMonth = new YearMonth(info.getLocalDate());
if (monthCounts does not contains yearMonth) {
monthCounts.put(yearMonth, info.count);
} else {
oldCount = monthCounts.get(yearMonth);
monthCounts.put(yearMonth, info.count + oldCount);
}
}
// feel free to output content of monthCounts now.
// And, with TreeMap, the content of monthCounts are sorted
You are looking for the getMonthOfYear and getYear methods on the LocalDate class in Joda-Time 2.3.
for ( Info info : infos ) {
int year = info.day.getYear();
int month = info.day.getMonthOfYear();
}
From there, write code to roll-up the count in any way that suits you. You could keep a map of years as keys leading to a map of months. You could create a string in the format of "YYYY-MM" as a key to map.

Categories

Resources