I'm writing a C# console application where you enter your name and birthdate in yyyy/mm/dd format to have the console tell you your age in years and months. Now I've got that part figured out and it works. Until I tried to also implement a try and catch exception to check if the date you entered was in the right format. If not it should tell you to try again 3 times before telling you the date format is incorrect and then quitting the app.
Now the problem is the app works sort of, but it tells you the date format is incorrect even when it isn't. Then still continues to give the correct output after looping through the app that asks for name and date of birth 3 times. This is the code I have so far(I know the year month output is a bit messy I just spent way too long testing too much stuff to try and change it now, I am open to improvements and changes though):
namespace CSConsoleDateTimeTypes
{
class Program
{
static int Count = 0;
static void Main(string[] args)
{ EnterDate(); }
static void EnterDate()
{
string userName, enteredDoBString;
Console.WriteLine("Enter your name:");
userName = Console.ReadLine();
Console.WriteLine("Enter your date of birth in the format yyyy/mm/dd:");
enteredDoBString = Console.ReadLine();
string dateString = Console.ReadLine();
parseDateString(dateString);
DateTime enteredDoB = DateTime.Parse(enteredDoBString);
Console.WriteLine("Your DoB is: {0}", enteredDoB);
DateTime dateToday = DateTime.Today;
if (dateToday < enteredDoB)
{
DateTime date4 = dateToday;
dateToday = enteredDoB;
enteredDoB = date4;
}
TimeSpan ts = dateToday - enteredDoB;
//total days (irrelevant to the application though)
Console.WriteLine(ts.TotalDays);
//total years
int years = dateToday.Year - enteredDoB.Year;
int months = 0;
//Total months
if (dateToday.Month < enteredDoB.Month)
{
months = 12 - dateToday.Month + enteredDoB.Month;
}
else
{
months = enteredDoB.Month - dateToday.Month;
}
if (months > 12)
{
Console.WriteLine("Years: {0}, Months: {1}", years - 1, 12 - (months - 12));
}
else if (months < 0)
{
Console.WriteLine("Years: {0}, Months: {1}", years, months - months);
}
else
{
Console.WriteLine("Years: {0}, Months: {1}", years, months);
}
Console.ReadKey();
Console.ReadKey();
}
static void parseDateString(string datestring)
{
try
{
DateTime date3 = DateTime.Parse(datestring, System.Globalization.CultureInfo.InvariantCulture);
date3.ToShortDateString();
Console.ReadKey();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
//if date was entered incorrectly 3 times, the application should exit..
Count++;
if (Count < 3)
{
EnterDate();
}
else
{
Console.WriteLine("\aSorry date still not in correct format - Press any key to exit the application");
Console.ReadKey();
}
}
}
}
}
This is the output it gives when I launch the app and it finishes running through all the code after my inputs:
Enter your name:
gerrit
Enter your date of birth in the format yyyy/mm/dd:
1997/02/13
String was not recognized as a valid DateTime.
Enter your name:
gerrit
Enter your date of birth in the format yyyy/mm/dd:
1997/02/13
String was not recognized as a valid DateTime.
Enter your name:
gerrit
Enter your date of birth in the format yyyy/mm/dd:
1997/02/13
String was not recognized as a valid DateTime.
Sorry date still not in correct format - Press any key to exit the application
Your DoB is: 1997/02/13 12:00:00 AM
7294
Years: 20, Months: 0
Your DoB is: 1997/02/13 12:00:00 AM
7294
Years: 20, Months: 0
Your DoB is: 1997/02/13 12:00:00 AM
7294
Years: 20, Months: 0
As you can see it asks for name and date of birth 3 times and still telling me date format is incorrect then it gives the correct output (Your DoB is: 1997/02/13 12:00:00 AM
7294
Years: 20, Months: 0) 3 times
It should ask once and output once but I can't figure out how to do it. Any help would be highly appreciated.
Here is a screenshot of the console output if it helps at all
http://i.imgur.com/qUpF0g2.png
I changed a little your code.
I don't have checked the rest of your code, only to ask the date.
private static void Main(string[] args)
{
EnterDate();
}
private static void EnterDate()
{
Console.WriteLine("Enter your name:");
var userName = Console.ReadLine();
// ask for date
var enteredDoBString = AskForDate();
if (enteredDoBString == null)
return;
DateTime enteredDoB = DateTime.Parse(enteredDoBString);
Console.WriteLine($"Your DoB is: {enteredDoB}");
DateTime dateToday = DateTime.Today;
if (dateToday < enteredDoB)
{
DateTime date4 = dateToday;
dateToday = enteredDoB;
enteredDoB = date4;
}
TimeSpan ts = dateToday - enteredDoB;
// total days (irrelevant to the application though)
Console.WriteLine(ts.TotalDays);
// total years
var years = dateToday.Year - enteredDoB.Year;
var months = 0;
// Total months
if (dateToday.Month < enteredDoB.Month)
{
months = 12 - dateToday.Month + enteredDoB.Month;
}
else
{
months = enteredDoB.Month - dateToday.Month;
}
if (months > 12)
{
Console.WriteLine($"Years: {years - 1}, Months: {12 - (months - 12)}");
}
else if (months < 0)
{
Console.WriteLine($"Years: {years}, Months: {months - months}");
}
else
{
Console.WriteLine($"Years: {years}, Months: {months}");
}
Console.ReadKey();
Console.ReadKey();
}
private static string AskForDate()
{
var count = 0;
while (count++ < 3)
{
try
{
Console.WriteLine("Enter your date of birth in the format yyyy/mm/dd:");
return DateTime.Parse(Console.ReadLine(), System.Globalization.CultureInfo.InvariantCulture).ToShortDateString();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
//if date was entered incorrectly 3 times, the application should exit..
}
}
Console.WriteLine("\aSorry date still not in correct format - Press any key to exit the application");
Console.ReadKey();
return null;
}
What I made:
I removed your function parseDateString and create a new called AskForDate. This function, like the name says, ask for the date to the user, and inside this function, the date entered is checked if is valid or not.
I believe that is better to check and ask on same function.
If the date entered by user is correct, the date is returned as ToShortDateString. If the date is incorrectly, the function ask two more times, and on third time, a null is returned.
Then, in the EnterDate function, if null is returned from AskForDate function, the program exits.
I also changed some strings interpolations, and removed some variables.
Related
I am building a c # console application.
Assume user inputs as
no of effort for task in hours = 48
no of working hours per day = 9
start date = 26/02/2021
How can I display the end date of the task after excluding the weekends and public holidays.
I have already implemented the user inputs by considering all possible validations.
static void Main(string[] args)
{
//effort hours
Console.Write("Enter No of hours: ");
int hours;
if (Int32.TryParse(Console.ReadLine(), out hours))
{
if (hours <= 0)
{
Console.WriteLine("Hours of effort cannot be a negative value or 0");
}
else
{
Console.WriteLine("The no of hours entered is: " + hours);
}
}
else
{
Console.WriteLine("You have entered an incorrect value.");
}
Console.ReadLine();
//working hours per day
Console.Write("Enter No of working hours per day: ");
int WorkingHours;
if (Int32.TryParse(Console.ReadLine(), out WorkingHours))
{
if (WorkingHours <= 0 || WorkingHours > 9)
{
Console.WriteLine("Maximum working hours per day is 9 hours and no of hours entered cannot be 0 or negative");
}
else
{
Console.WriteLine("The no of working hours entered is: " + WorkingHours);
}
}
else
{
Console.WriteLine("You have entered an incorrect value.");
}
Console.ReadLine();
//Enter start date
Console.WriteLine("Enter the start date date (e.g. dd/mm/yyyy): ");
DateTime startDate;
{
while (!DateTime.TryParse(Console.ReadLine(), out startDate))
{
Console.WriteLine("You have entered an incorrect value.");
Console.WriteLine("Enter the start date date (e.g. dd/mm/yyyy): ");
}
Console.WriteLine("The startdate is: " + startDate);
}
}
The easiest way to solve this problem without looping is like this:
static void Main ( string[] args ) {
BeginRoutine:
//effort hours
Console.Write( "Enter No of hours: " );
int hours;
if ( Int32.TryParse( Console.ReadLine(), out hours ) ) {
if ( hours <= 0 ) {
Console.WriteLine( "Hours of effort cannot be a negative value or 0" );
}
else {
Console.WriteLine( "The no of hours entered is: " + hours );
}
}
else {
Console.WriteLine( "You have entered an incorrect value." );
}
//Console.ReadLine();
//working hours per day
Console.Write( "Enter No of working hours per day: " );
int WorkingHours;
if ( Int32.TryParse( Console.ReadLine(), out WorkingHours ) ) {
if ( WorkingHours <= 0 || WorkingHours > 9 ) {
Console.WriteLine( "Maximum working hours per day is 9 hours and no of hours entered cannot be 0 or negative" );
}
else {
Console.WriteLine( "The no of working hours entered is: " + WorkingHours );
}
}
else {
Console.WriteLine( "You have entered an incorrect value." );
}
//Console.ReadLine();
GetStartDate:
//Enter start date
Console.WriteLine( "Enter the start date date (e.g. dd/mm/yyyy): " );
DateTime startDate;
while ( !DateTime.TryParse( Console.ReadLine(), out startDate ) ) {
Console.WriteLine( "You have entered an incorrect value." );
Console.WriteLine( "Enter the start date date (e.g. dd/mm/yyyy): " );
}
// Make sure the start date isn't a Saturday or Sunday!
if ( startDate.DayOfWeek == DayOfWeek.Saturday || startDate.DayOfWeek == DayOfWeek.Sunday ) {
Console.WriteLine( "Cannot start work on {0} because it is a {1}",
startDate.ToString( "MM/dd/yyyy" ), startDate.DayOfWeek );
goto GetStartDate;
}
Console.WriteLine( "The startdate is: " + startDate );
// Determine number of work days:
double workDays = hours / WorkingHours;
Console.WriteLine( "\nTask will take {0} work days", workDays.ToString("0.00") );
// Determine total weeks and days:
double totalWeeks = workDays / 5D;
double totalDays = ( totalWeeks * 7D );
// Print statistics to Console for user
Console.WriteLine( "Task will take {0} weeks and {1} total calender days ...",
totalWeeks.ToString( "0.00" ), totalDays.ToString( "0.00" ) );
// Calculate ending date and display it:
DateTime endDate = startDate.AddDays(totalDays);
Console.WriteLine( "The ending date will be {0}", endDate.ToString( "MM/dd/yyyy" ) );
// Prompt user to restart:
Console.WriteLine( "\n\nProgram complete ... press Y to restart or any other key to continue.\n" );
if ( Console.ReadKey( true ).Key == ConsoleKey.Y ) goto BeginRoutine;
}
I haven't exhaustively tested this routine against all possible scenarios, and it's surely not the "best" way to do this (for instance, it doesn't account for holidays like Christmas and is not localized for regions and cultures) but it seems to solve your simple problem in a quick and performant manner. Oddly enough, I was just writing some pretty interesting DateTime code for my strategy game prototype where I use the game loop to drive a DateTime forward and create an in-game time system.
EDIT: Note that I pretty much left your original code intact and just added beneath it ... an easy way to solve for holidays would be to create a list of dates containing holidays, see if any fall in between start date and end date (perhaps with a custom query) and just add a day for each one that is.
As mentioned in the comments, you would need to provide Holiday List which would be different across the world. Additionally, the defined "workdays"/"weekends" could also vary depending on the region you are developing the application for. For example, some of the middle-east countries have weekends on Thursday/Friday.
Assuming you have regular Saturday/Sunday weekends, you could modify the DateTime Extension provided by FluentDateTime as following to include a collection of Holidays
public static class Extentions
{
public static DateTime AddBusinessDays(this DateTime current, int days,IEnumerable<DateTime> holidayList)
{
var sign = Math.Sign(days);
var unsignedDays = Math.Abs(days);
var holidayCollection = new HashSet<DateTime>(holidayList);
for (var i = 0; i < unsignedDays; i++)
{
do
{
current = current.AddDays(sign);
} while (current.DayOfWeek == DayOfWeek.Saturday
|| current.DayOfWeek == DayOfWeek.Sunday
|| holidayCollection.Contains(current));
}
return current;
}
}
You could now use the method as
startDate.AddBusinessDays(totalHours/perDayHours,holidayList)
If as mentioned earlier, you would need to consider a different weekend, you need to make appropriate changes in the code above.
PS: Above code assumes you are interested only in "EndDate" and not to accurate hour.
I need to accept input paramteters and print date range in console like in the example:
input: "01.01.2017 05.01.2017"
output: "01 - 05.01.2017"
So as you see dates must be separated with dots and printed with dash between them. What is more, if start and end date both has the same month and year, these are printed only once.
Does anyone can suggest good way to achieve this?
Just format date as you need and add aditional check for cases.
DateTime date1 = new DateTime();
DateTime date2 = new DateTime();
//while not valid input dates format...
bool valid = false;
while (!valid)
{
Console.WriteLine("Enter start date:");
string dateEntered1 = Console.ReadLine();
Console.WriteLine("Enter end date:");
string dateEntered2 = Console.ReadLine();
bool isvalidDate1 = DateTime.TryParse(dateEntered1,out date1);
bool isvalidDate2 = DateTime.TryParse(dateEntered2,out date2);
//check if date parsing was sucess
if(isvalidDate1 && isvalidDate2)
{
valid = true;
}
else
{
Console.WriteLine("Dates entered is in incorrect format!");
}
}
string period = "";
if (date1.Month == date2.Month && date1.Year == date2.Year)
{
period = string.Format("{0} - {1}", date1.ToString("dd."), date2.ToString("dd.MM.yyyy"));
}
else
{
period = string.Format("{0} - {1}", date1.ToString("dd.MM.yyyy"), date2.ToString("dd.MM.yyyy"));
}
Console.Write(period);
Console.Read();
I'm not a C# expert so please keep that in mind while I ask this:
In my C# I have a forms project where the user enters the year,month and day they were born and it tells them the day of week their birthday was on.
I want to make sure the user doesn't enter a date that doesn't exist example:
Feb 30 2018.
So, I want to create a popup message that says "date doesn't exist" to do this I created this code:
static string FindDay(int year, int month, int day)
{
//The reason why we are using a new keyword is because i belive: we are creating a new object and to do that you must use a new keyword.
//DateTime is its own data type like int or string.
DateTime birthdayDate = new DateTime(year, month, day);
string dayOfWeek = birthdayDate.DayOfWeek.ToString(); //Don't confuse the local dayOfWeek varible with the DayOfWeek property
return dayOfWeek;
}
private void FindButton_Click(object sender, EventArgs e)
{
//The reason(I think) that we are casting to int data types is because its a "DateTime" data type.
int year = (int)numericYear.Value;
int month = (int)numericMonth.Value;
int day = (int)numericDay.Value;
//Date checking to maek sure date isn't invaild.
int maxDays = DateTime.DaysInMonth(year, month);
if (day > maxDays)
{
MessageBox.Show("Invaild date");
}
string dayString = FindDay(year, month, day);
MessageBox.Show("You were born on a:" + dayString);
}
But when I run in the program everything runs fine and the message pops up and then after the message I see this:
ERROR:
System.ArgumentOutOfRangeException: 'Year, Month, and Day parameters describe an un-representable DateTime.'
And it pops up at
string dayOfWeek = birthdayDate.DayOfWeek.ToString();
How can I fix this issue and why is it happening?
int maxDays = DateTime.DaysInMonth( year, month ); // set a breakpoint here, and see what happens
if ( day > maxDays )
{
MessageBox.Show("Invaild date");
}
else
{
string dayString = FindDay(year, month, day);
MessageBox.Show("You were born on a:" + dayString);
}
If you don't have to show message to explain why the date is not valid you can simply TryParseExact it into a DateTime.
No need to convert to int, To check the number of day in the month.
var inputs = new List<inputDate>
{
new inputDate(1,1,2018),
new inputDate(32,1,2018),
new inputDate(1,13,2018),
new inputDate(1,1,-2018)
};
foreach (var input in inputs)
{
GetDayOfBirth(input);
}
private void GetDayOfBirth(inputDate input)
{
CultureInfo invC = CultureInfo.InvariantCulture;
if (DateTime.TryParseExact(
$"{input.D}/{input.M}/{input.Y}",
$"d/M/yyyy",
invC,
DateTimeStyles.None,
out DateTime birthday)
)
{
Console.WriteLine("You were born on a:" + birthday.DayOfWeek);
return;
}
Console.WriteLine("Invalid date");
}
I have the time and date system working for today, tomorrow and for a set date. Now I want to create some sort of Console.Read for the system so that you can input any date and receive the corresponding day.
static void date()
{
DateTime now = DateTime.Today;
Console.WriteLine("Today's date is {0}\n", now);
DateTime currTimeAndDate = DateTime.Now;
Console.WriteLine("Today's time and date is {0}\n", currTimeAndDate);
DateTime tomorrow = currTimeAndDate.AddDays(1);
Console.WriteLine("Tomorrow's date will be {0}\n", tomorrow);
DateTime then = new DateTime(1995,4,28);
Console.WriteLine("I was born {0}\n", then.DayOfWeek);
Console.Write("Press any key to continue.....\n");
Console.ReadLine();
}
static void inputDate()
{
Console.ReadLine();
}
}
}
Since this is a console application, I would recommend using the TryParse method, as follows.
Console.WriteLine("Enter a date: ");
DateTime userDateTime;
if (DateTime.TryParse(Console.ReadLine(), out userDateTime))
{
Console.WriteLine("The day of the week is: " + userDateTime.DayOfWeek);
}
else
{
Console.WriteLine("You have entered an incorrect value.");
}
Console.ReadLine();
It depends on how you want to be able to have the user to input the dates. You could have them input a month, day and year separately, like so:
Console.Write("Enter a month: ");
int month = int.Parse(Console.ReadLine());
Console.Write("Enter a day: ");
int day = int.Parse(Console.ReadLine());
Console.Write("Enter a year: ");
int year = int.Parse(Console.ReadLine());
DateTime inputtedDate = new DateTime(year, month, day);
If you want, you could have them enter an actual date:
Console.Write("Enter a date (e.g. 10/22/1987): ");
DateTime inputtedDate = DateTime.Parse(Console.ReadLine());
Keep in mind that these are examples. In a real program, you should check to make sure the values entered are real. Also, instead of DateTime.Parse(), you could use DateTime.ParseExact() to be able to allow the user to enter the date in a custom format.
I'm writing a program where the user has to enter a date. My questions are:
How can I set the date to today and the past but NOT the future?
How can I set the date to non-US format, i.e. dd/mm/yyyy, so the compiler reads the middle value as month?
This is what my code looks like:
static DateTime date;
and a method like this...
public static void EnterDates()
{
for (int i = 0; i < days; i++)
{
Console.Write("Enter the date (dd/mm/yyyy): ");
date = DateTime.Parse(Console.ReadLine());
centers[k].dates[i] = date;
Console.WriteLine("Day " + centers[k].dates[i]);
Console.Write("Number of movie screenings: ");
movieScreen = Convert.ToInt32(Console.ReadLine());
centers[k].movieScreen[i] = movieScreen;
Console.Write("Total number of customers: ");
customers = Convert.ToInt32(Console.ReadLine());
centers[k].customers[i] = customers;
centers[k].revenue[i] = movieScreen * customers * (centers[k].Price * 1.13);
centers[k].totalRevenue += centers[k].revenue[i];
How can I set the date to today and the past but NOT the future?
Based on what you currently have, you can add a validation after the user enters the date and compare it to DateTime.Now
if(date < DateTime.Now)
//valid
else
//invalid
How can I set the date to non-US format, i.e. dd/mm/yyyy, so the
compiler reads the middle value as month?
You could use DateTime.ParseExact
date = DateTime.ParseExact(Console.ReadLine(), "dd/MM/yyyy", CultureInfo.InvariantCulture)