My program is currently working to get the next day except I seem to have an array to which I want removing. Whenever I remove the array within my Day property then my month is having an issue. Any ideas for a solution towards this issue. Please do not mention me not wanting to use DateTime or whatever, as I am doing this, as a challenge for myself. Basically the issue is when I remove my array I am having a problem or issue with the month and this array is useless, as I have if statements within my nextDay method.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace date
{
class Program
{
static void Main(string[] args)
{
string british, american; // sets two strings one for british and other for american
Console.Title = "NextDate Application";
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("\t\t\t\t\t\tNextDate Application\n\t\t\t\t\t-------------------------------------"); // title
Console.ResetColor();
Console.WriteLine("This application will allow you to enter a valid date and this will get the next day."); // intro of what the application does
Console.WriteLine("The application takes leap years into account\n"); // intro of what the application does
Console.WriteLine("enter key 'b' for British Format or 'a' for American Format"); // writes the line
char key = Console.ReadKey().KeyChar;
if (key == 'b') // if key b is entered
{
british = GetValidInput("\nplease enter date as dd/MM/yyyy\n"); // tells user to input a date in the format
int day; // sets variable
int month; // sets variable
int year; // sets variable
Date date; // instance of class Date
string[] read = british.Split('/'); // "/" can be read from each value and sets new array
day = int.Parse(read[0]); // day is first position in array
month = int.Parse(read[1]); // month is second position in array
year = int.Parse(read[2]); // year is third position in array
try
{
date = new Date(day, month, year); // initialises a new date class
for (int i = 0; i < 1; i++)
{
date.nextDay(); // calls nextDay method
Console.WriteLine("{0}/{1}/{2}", date.Day, date.Month, date.Year); // writes the line in a format of d/m/y
Console.ReadLine(); // reads the line
}
}
catch (ArgumentOutOfRangeException exc)
{
Console.WriteLine(exc.Message); // states the message for ArgumentOutOfRangeException
Console.Read(); // breaks
}
}
else if (key == 'a')
{
american = GetValidInput("\nplease enter date as MM/dd/yyyy\n"); // tells user to input a date in the format
int day; // sets variable
int month; // sets variable
int year; // sets variable
Date date; // instance of class Date
string[] read = american.Split('/'); // "/" can be read from each value and sets new array
month = int.Parse(read[0]); // month is first position in array
day = int.Parse(read[1]); // day is second position in array
year = int.Parse(read[2]); // year is third position in array
try
{
date = new Date(day, month, year); // initialises a new date class
for (int i = 0; i < 1; i++)
{
date.nextDay(); // calls nextDay method
Console.WriteLine("{0}/{1}/{2}", date.Month, date.Day, date.Year); // writes the line in a format of m/d/y
Console.ReadLine(); // reads the line
}
}
catch (ArgumentOutOfRangeException exc)
{
Console.WriteLine(exc.Message); // states the message for ArgumentOutOfRangeException
Console.Read(); // breaks
}
}
}
static string GetValidInput(string prompt)
{
while (true)
{
string input;
Console.WriteLine(prompt);
input = Console.ReadLine();
if (!string.IsNullOrEmpty(input))
{
return input;
}
Console.WriteLine("error no input");
}
}
class Date
{
private int _month; // 1-12
private int _day; // 1-31 depending on month
private int _year; // sets the year
public Date(int day, int month, int year)
{
Month = month;
Day = day;
Year = year;
}
public void nextDay() // nextDay method
{
{
if (_day == 31 && _month == 1) // jan
{
_day = 1;
_day = _day - 1;
_month = 2;
}
if (_day == 28 && _month == 2) // feb
{
_day = 1;
_day = _day - 1;
_month = 3;
}
if (_day == 31 && _month == 3) // march
{
_day = 1;
_day = _day - 1;
_month = 4;
}
if (_day == 30 && _month == 4) // april
{
_day = 1;
_day = _day - 1;
_month = 5;
}
if (_day == 31 && _month == 5) // May
{
_day = 1;
_day = _day - 1;
_month = 6;
}
if (_day == 30 && _month == 6) // June
{
_day = 1;
_day = _day - 1;
_month = 7;
}
if (_day == 31 && _month == 7) // July
{
_day = 1;
_day = _day - 1;
_month = 8;
}
if (_day == 31 && _month == 8) // Aug
{
_day = 1;
_day = _day - 1;
_month = 9;
}
if (_day == 30 && _month == 9) // Sept
{
_day = 1;
_day = _day - 1;
_month = 10;
}
if (_day == 31 && _month == 10) // Oct
{
_day = 1;
_day = _day - 1;
_month = 11;
}
if (_day == 30 && _month == 11) // Nov
{
_day = 1;
_day = _day - 1;
_month = 12;
}
if (_day == 31 && _month == 12) // Dec
{
_day = 1;
_month = 1;
_year = _year + 1;
}
else
{
_day = _day + 1;
}
}
}
public int Year // property called Year
{
get { return _year; } // return the year
set // set statement
{
if (value >= 1820 && value <= 2020) // if value is higher than or equal to 1820 and less than or equal to 2020
_year = value; // sets year as value
else
throw new ArgumentOutOfRangeException("Year must be between 1820 and 2020"); // throws an exception
}
}
public int Month // property called Month
{
get { return _month; } // return month
set // set statement
{
if (value > 0 && value <= 12) // if value is higher than 0 and less than or equal to 12
_month = value; // sets month as value
else
throw new ArgumentOutOfRangeException("Month must be between 1-12"); // throws an exception
}
}
public int Day // property called Day
{
get { return _day; }
set
{
// array Max days of each month
int[] days = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
if (value > 0 && value <= days[_month]) // if value is higher than 0 and less than or equal to days of month
_day = value; // sets day as value
// check for the leap year
else if (_month == 2 && value == 29 && // else if month is equal to 2 and value is equal to 29
(_year % 400 == 0 || (_year % 4 == 0 && _year % 100 != 0)))
_day = value;
else
throw new ArgumentOutOfRangeException("Day is out of range"); // throws an exception
}
}
}
}
}
There are several issues:
Each if block is being evaluated independently:
if (...)
{
}
if (...)
{
}
else
{
}
The else block here is only paired with the if block before it. Instead, you should be using else if in the middle ones.
After you make the above change, then you can remove the extraneous _day = _day - 1; calls.
The February check needs to account for leap year.
if (_day == 28 && _month == 2)
Should be
if (_month == 2 && (_day == IsLeapYear(_year) ? 29 : 28))
If you don't want to use DateTime.IsLeapYear, then extract your implementation from the Day setter into a method and use it in both places.
Regarding your question:
Whenever I remove the array within my Day property...
The only array in your Day property is the one called days, which you are indeed using correctly in your logic, so it doesn't make sense to remove it.
Related
How do i use operands in this code? What can i do to resolve this problem? Any suggestions or links to tutorials would be appreciated.
Operator '%' cannot be applied to operands of type 'string' 'int'
int i = 0;
double[] arr1 = new double[20];
for (i = 0; i < 20; i++)
{
Console.Write("Enter a number (0=stop): ");
var year = Console.ReadLine();
if (year == "0") break;
arr1[i] = int.Parse(year);
while (year != 0)
{
if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))
{
Console.WriteLine($"{year} is a leap year.");
}
else if (year < 0)
{
Console.WriteLine($"Year must be positive!");
}
else
{
Console.WriteLine($"{year} is not a leap year.");
}`
You are close. You are already parsing the string to an int. Just use that instead of the string year when doing your calculations. Also, I'm not sure what you're trying to do with that while loop but I don't think you need it. It seems to just cause your program to go in an infinite loop because while is evaluating year but there is no opportunity to change the year value within the while loop.
void Main()
{
int i = 0;
double[] arr1 = new double[20];
for (i = 0; i < 20; i++)
{
Console.Write("Enter a number (0=stop): ");
var line = Console.ReadLine();
int numYear = int.Parse(line);
arr1[i] = numYear;
string message = "" ;
if (line != "0")
{
if (numYear < 0)
{
message = "Year must be positive!";
}
else if ((numYear % 4 == 0) && (numYear % 100 != 0)) || (numYear % 400 == 0))
{
message = $"{numYear} is a leap year.");
}
else
{
message = $"{numYear} is not a leap year.");
}
Console.WriteLine(message);
}
}
}
using System;
using System.Text.RegularExpressions;
namespace calendar
{
class Program
{
static void Main()
{
int year;
int day;
string[] month = new string[] { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
int[] days = new int[] { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
Console.Write("Enter the year for which you wish to generate the calendar >> ");
int.TryParse(Console.ReadLine(), out year); // Validate //
Console.Write("Enter the day of the week that January first is on >> ");
int.TryParse(Console.ReadLine(), out day); // Validate //
while (day > 31 || day < 1) // Reprompt for value if date is out of range //
{
Console.WriteLine("Enter a valid date >> ");
Console.Write("Enter the day of the week that January first is on >> ");
int.TryParse(Console.ReadLine(), out day); // Validate //
}
switch (LeapYear(year)) // Switch statement checks if Leap Year is true //
{
case true:
days[1] += 1;
Console.WriteLine("Calendar for year - {0}", year);
for (int i = 0; i < month.Length; i++)
{
Console.WriteLine("\n" + month[i]);
day = DisplayCalender(days[i], day);
Console.Write("\n");
}
break;
}
}
public static int DisplayCalender(int days, int start) //Display Function//
{
int startDay = start;
Console.WriteLine("Sun\tMon\tTue\tWed\tThu\tFri\tSat");
for (int i = 0; i < start; i++)
Console.Write("\t");
for (int i = 1; i <= days; i++)
{
if (startDay > 6)
{
startDay = 0;
Console.WriteLine();
}
Console.Write(i + "\t");
startDay++;
}
return startDay;
}
public static Boolean LeapYear(int year)
{
if ((year % 400 == 0) || ((year % 4 == 0) && !(year % 100 == 0))) // Checks each OR AND statements and return true or false //
{
return true;
}
else
return false;
}
}
}
I'm imagining the problem you're describing is having a month that starts on Sunday is making the calendar skip an entire line. Like the image:
That is happening because your method public static int DisplayCalender(int days, int start) is receiving the parameter int start with a value of 7.
That makes write tabs on the whole week on your first for and then skip the line on the second for.
To solve the issue you can simply reassign startDay with zero when it is 7 and check on you tab loop for startDay instead of start:
public static int DisplayCalender(int days, int start) //Display Function//
{
int startDay = start == 7 ? 0 : start;
Console.WriteLine("Sun\tMon\tTue\tWed\tThu\tFri\tSat");
for (int i = 0; i < startDay; i++)
Console.Write("\t");
for (int i = 1; i <= days; i++)
{
if (startDay > 6)
{
startDay = 0;
Console.WriteLine();
}
Console.Write(i + "\t");
startDay++;
}
return startDay;
}
This will give you the expected result:
What can you improve from here?
Making all that from scratch probably made you learn a lot about loop and flow. If you have some time check on DateTime.
There you have methods to find leap years, day of the week, and Month. That would help you simplify your code a lot.
Welcome to StackOverflow!
First I must say you are overcomplicating this very much, there is a perfect date library out of the box that you could have used.
For example:
DateTime now = DateTime.Now;
bool isLeapYear = DateTime.IsLeapYear(now.Year);
int daysInCurrentMonth = DateTime.DaysInMonth(now.Year, now.Month);
Instead of this:
Console.WriteLine("Sun\tMon\tTue\tWed\tThu\tFri\tSat");
for (int i = 0; i < start; i++)
Console.Write("\t");
Do this:
Console.WriteLine("Sun\tMon\tTue\tWed\tThu\tFri\tSat");
if (start < 7)
{
for (int i = 0; i < start; i++)
{
Console.Write("\t");
}
}
And instead of this:
if (startDay > 6)
{
startDay = 0;
Console.WriteLine();
}
do this:
if (startDay > 6)
{
startDay = 0;
if (i!=1)
{
Console.WriteLine();
}
}
So DisplayCalender method should look like this:
public static int DisplayCalender(int days, int start) //Display Function//
{
int startDay = start;
Console.WriteLine("Sun\tMon\tTue\tWed\tThu\tFri\tSat");
if (start < 7)
{
for (int i = 0; i < start; i++)
{
Console.Write("\t");
}
}
for (int i = 1; i <= days; i++)
{
if (startDay > 6)
{
startDay = 0;
if (i != 1 )
{
Console.WriteLine();
}
}
Console.Write(i + "\t");
startDay++;
}
return startDay;
}
e.g. 70,105 - calculate any date of birth that meets the age range of the parameters
CalculateDob(int youngestAge, int oldestAge)
{
Random r = new Random();
int age = 0;
age = r.Next(70, 105);
var year = DateTime.Now.Year - age;
var month = r.Next(1, 12);
var day = r.Next(1, 28);
return new DateTime(year, month, day);
}
My current soluton almost works, but fails in some edge cases i.e. returns 69 in some circumstances due what i presume a month issue.
Any suggestions?
Reason you are getting 69 years of age sometimes is because if CalculateDob returns month which is after current month (DateTime.Now); then Dob still wouldn't reach 70 years. Also, you should bring random constructor out from the method, and make it static so that you don't keep seeding rand generator during every call.
public static void Main(string[] args)
{
for (int i = 0; i < 100; i++)
{
var birthDate = CalculateDob(70, 105);
var now = DateTime.Now;
int age = now.Year - birthDate.Year;
if (now.Month < birthDate.Month || (now.Month == birthDate.Month && now.Day < birthDate.Day))
{
age--;
}
Console.WriteLine(age);
}
}
//Construct this as static so that we don't keep seeding the rand
private static readonly Random _random = new Random();
static DateTime CalculateDob(int youngestAge, int oldestAge)
{
int age = 0;
age = _random.Next(70, 105);
var today = DateTime.Now;
var year = today.Year - age;
var month = _random.Next(1, 12);
//Age might less than youngest age,
//if born at/after current month, edge condition
if (month >= today.Month)
{
month = today.Month - 1;
if (month < 1)
{
year--;
month = 12;
}
}
var day = _random.Next(1, DateTime.DaysInMonth(year, month));
return new DateTime(year, month, day);
}
I am currently having problems with this loop. It becomes an infinite loop and i get a stack overflow error. This is for a interest rate trade swap application. i is the length of the trade and l is the increasing index.
private void button1_Click(object sender, EventArgs e)
{
int outp = 0;
int i = int.Parse(tradeLength.Text);
string month = "January";
for (int l = 1; l <= i; l++)
{
Console.WriteLine("I iterated " + l + " Amount of times");
if (l == 1)
{
month = "January";
}
if (l == 2)
{
month = "February";
}
if (l == 3)
{
month = "March";
}
if (l == 4)
{
month = "Aprll";
}
if (l == 5)
{
month = "May";
}
if (l == 6)
{
month = "June";
}
if (l == 7)
{
month = "July";
}
if (l == 8)
{
month = "August";
}
if (l == 9)
{
month = "September";
}
if (l == 10)
{
month = "October";
}
if (l == 11)
{
month = "November";
}
if (l == 12)
{
month = "December";
}
else
{
month = "Null";
l = 1;
}
The cause is the final else:
if (l == 12) {
month = "December";
}
else { // <- if l != 12 (e.g. l == 1) restart the loop
month = "Null";
l = 1;
}
you want else if:
if (l == 1)
{
month = "January";
}
else if (l == 2)
{
...
}
...
else if (l == 12)
{
...
}
else {
month = "Null";
l = 1;
}
Edit: Another problem (see FKEinternet's comment) is a user input: if i is greater than 12 l never reaches it. You have to either validate the user input:
int i = int.Parse(tradeLength.Text);
if (i > 12)
i = 12; // or ask for other value
or use modular arithmetics:
for (int index = 1; index <= i; index++) {
int l = index % 12 + 1;
if (l == 1)
{
month = "January";
}
else if (l == 2)
...
else if (l == 12)
...
else
{
month = "Null";
l = 1;
}
}
It is not a very good idea to set the loop variable inside the loop. Like #stuartd pointed out, in your else line you set the loop variable to 1 and causing the loop to start all over again. Remove the l=1 line in your else block.
I presume you want to go to next year when i > 12. The way your code is made, when this happens, you get to loop forever, because "l" never reaches a number bigger than 12, it becomes 1 when it hits 13 and starts over.
To fix this, instead of
if (l == 1)
you want to use
if ((l % 12) == 1)
so your entire loop would be like this:
for (int l = 1; l <= i; l++)
{
Console.WriteLine("I iterated " + l + " Amount of times");
if ((l % 12) == 1)
{
month = "January";
}
if ((l % 12) == 2)
{
month = "February";
}
if ((l % 12) == 3)
{
month = "March";
}
if ((l % 12) == 4)
{
month = "Aprll";
}
if ((l % 12) == 5)
{
month = "May";
}
if ((l % 12) == 6)
{
month = "June";
}
if ((l % 12) == 7)
{
month = "July";
}
if ((l % 12) == 8)
{
month = "August";
}
if ((l % 12) == 9)
{
month = "September";
}
if ((l % 12) == 10)
{
month = "October";
}
if ((l % 12) == 11)
{
month = "November";
}
if ((l % 12) == 0)
{
month = "December";
}
{
PS = this is really not the right way to do this, I'm just using your own code and making the least amount of mods for it to work as intented. Good luck!
I have a Java application I'm trying to convert to C#. I have solved a fair bit of the program, but I have this clear method that troubles me:
private void checkCourts()
{
if (splMonth.getSelectedValue() != null && splDate.getSelectedValue() != null)
{
courtModel.clear();
Calendar booking = new GregorianCalendar();
int year = Calendar.getInstance().get(Calendar.YEAR);
int month = new Scanner(splMonth.getSelectedValue().toString()).nextInt() - 1;
int date = new Scanner(splDate.getSelectedValue().toString()).nextInt();
int time = Integer.parseInt(cmbxTime.getSelectedItem().toString());
int currentMonth = Calendar.getInstance().get(Calendar.MONTH);
int currentDate = Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
int currentTime = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
booking.set(year, month, date, time, 0, 0);
if (month > currentMonth || (month == currentMonth && date > currentDate) || (month == currentMonth && date == currentDate && time > currentTime))
{
try
{
ArrayList<Reservation> rs = BookingManager.getInstance().getReservations();
Reservation r = new Reservation(booking);
ArrayList<String> courtNames = BookingManager.getInstance().getCourtsName();
for (int i = 0; i < rs.size(); i++)
{
r.getReservationTime().clear(Calendar.MILLISECOND);
rs.get(i).getReservationTime().clear(Calendar.MILLISECOND);
}
if (!rs.contains(r))
{
for (String c : courtNames)
{
courtModel.addElement(c);
}
}
else
{
for (String c : courtNames)
{
courtModel.addElement(c);
}
for (int i = 0; i < rs.size(); i++)
{
if (r.getReservationTime().getTime().equals(rs.get(i).getReservationTime().getTime()))
{
String courtName = BookingManager.getInstance().getNameById(rs.get(i).getCourtId());
courtModel.removeElement(courtName);
}
}
}
splCourt.setModel(courtModel);
}
catch (Exception e)
{
System.out.println("ERROR - " + e.getMessage());
}
}
else
{
JOptionPane.showMessageDialog(null, "Den valgte dato er ikke tilgængelig for booking.", "Advarsel", JOptionPane.INFORMATION_MESSAGE);
}
}
}
Well, the top for loop is the real issue, I think. I would like to remove the reservation times that already have been booked.
This is my first for loop try-out:
private void checkCourts()
{
DateTime current = DateTime.Now;
int year = Int32.Parse(DateTimePicker.Value.ToString("yyyy"));
int currentYear = current.Year;
int month = Int32.Parse(DateTimePicker.Value.ToString("MM"));
int currentMonth = current.Month;
int day = Int32.Parse(DateTimePicker.Value.ToString("dd"));
int currentDay = current.Day;
int time = (int)cmbxTime.SelectedItem;
int currentTime = current.TimeOfDay.Hours;
string date1 = year.ToString() + "," + month.ToString() + "," + day.ToString();
DateTime thisdate = DateTime.Parse(date1);
thisdate = thisdate.AddHours(time);
List<Reservation> rs = BookingManager.getInstance().getReservations();
Reservation r = new Reservation(thisdate);
List<string> courtNames = BookingManager.getInstance().getCourtsName();
if (month > currentMonth || (month == currentMonth && day > currentDay) ||
(month == currentMonth && day == currentDay && time > currentTime) && year >= currentYear)
{
try
{
for (int i = 0; i < rs.Count; i++)
{
r.ReservationTime = r.ReservationTime.AddTicks(-r.ReservationTime.Ticks % 10000000);
rs[i].ReservationTime = rs[i].ReservationTime.AddTicks(-rs[i].ReservationTime.Ticks % 10000000);
}
if (!rs.Contains(r))
{
foreach (string c in courtNames)
{
lboxCourts.Items.Add(c);
}
}
else
{
foreach (string c in courtNames)
{
lboxCourts.Items.Add(c);
}
for (int i = 0; i < rs.Count; i++)
{
if (r.ReservationTime.Equals(rs[i].ReservationTime))
{
String courtName = BookingManager.getInstance().getNameById(rs[i].CourtId);
lboxCourts.Items.Remove(courtName);
MessageBox.Show("is equal");
}
}
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
else
{
MessageBox.Show("Den valgte dato er ikke gyldig! - vær opmærksom på at hvis du vælger dags dato, at tidspunktet ikke kan være tidligere end nuværende tidspunkt!");
}
}
Hope you can clear my sight.. I have simply lost focus. I know of what I have see online - that datetimepicker is not that easy to edit. But then I would just edit the already booked item - to something like "already booked".
According to the docs, your Java code .clear(Calendar.MILLISECOND) is simply removing any milliseconds from the value. It's not doing anything with your application logic to remove the actual reservation times. It doesn't appear to involve any kind of DateTimePicker either.
Assuming in c# that the ReservationTime is a DateTime property, and r.ReservationTime is a different property than rs[i].ReservationTime, then you would need to do the following:
for (int i = 0; i < rs.Count; i++)
{
r.ReservationTime = r.ReservationTime.AddTicks(-r.ReservationTime.Ticks % 10000000);
rs[i].ReservationTime = rs[i].ReservationTime.AddTicks(-rs[i].ReservationTime.Ticks % 10000000);
}
There are a couple of points to note:
Java's Calendar class has resolution to the millisecond, so removing milliseconds would be truncating the value to the second.
DateTime in .Net has resolution to the tick. I tick is 100 nanoseconds, so there are 10,000,000 ticks in a second.
Therefore, you can't just clear the milliseconds, you have to clear by computing the remainder of ticks smaller than one second. Those are then subtracted from the original value, getting you the same result.
DateTime in .Net is immutable, so you can't just change one property. You have to compute a new value, and then assign it back to the original variable.
It ended up like this:
for (int i = 0; i < rs.Count; i++)
{
r.ReservationTime = r.ReservationTime;
rs[i].ReservationTime = DateTime.Parse(rs[i].ReservationTime.ToString());
if (thisdate.CompareTo(rs[i].ReservationTime) != 0)
{
foreach (string c in courtNames)
{
lboxCourts.Items.Add(c);
}
}
else
{
lboxCourts.Items.Clear();
foreach (string c in courtNames)
{
lboxCourts.Items.Add(c);
}
for (int j = 0; j < rs.Count; j++)
{
if (r.ReservationTime.Equals(rs[j].ReservationTime))
{
string courtName = BookingManager.getInstance().getNameById(rs[j].CourtId);
lboxCourts.Items.Remove(courtName);
}
}
}
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
else
{
MessageBox.Show("Den valgte dato er ikke gyldig! - vær opmærksom på at hvis du vælger dags dato, at tidspunktet ikke kan være tidligere end nuværende tidspunkt!");
}
}
Thank you for your help... now my method is removing the already booked courts ;-)
Kindest regards
Rasmus