How to parse by one line? - c#

I am looking for a solution about how to get all of my int Parses within one line. At the moment when I start my program I have to enter day, month and year. It is all done line by line. I want a solution or method where this does all of my parsing within one line and within a format of "dd/MM/yyyy".
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)
{
Console.WriteLine("please enter date as dd/MM/yyyy");
int day;
int month;
int year;
day = int.Parse(Console.ReadLine());
month = int.Parse(Console.ReadLine());
year = int.Parse(Console.ReadLine());
Date i = new Date(day, month, year);
Console.WriteLine("{0}/{1}/{2}", i.day, i.month, i.year);
Console.ReadLine();
}
class Date
{
public int month; // 1-12
public int day; // 1-31 depending on month
int value = 1;
public int year
{
get;
private set;
}
public Date(int day, int month, int year)
{
this.day = day;
this.month = month;
this.year = year;
}
public int GetYear()
{
return year;
}
public void SetYear()
{
if (value > 1900 && value <= 2020)
year = value;
else
throw new ArgumentOutOfRangeException("year", value, "out of bounds");
}
private int Month
{
get { return month; }
set
{
if (value > 0 && value <= 12)
month = value;
else
throw new ArgumentOutOfRangeException("Month", value, "Month must be 1-12");
}
}
public int GetDay()
{
return day;
}
public void SetDay()
{
int[] days = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
if (value > 0 && value <= days[month])
day = value;
else if (month == 2 && value == 29 &&
year % 400 == 0 || (year % 4 == 0 && year % 100 != 0))
day = value;
else
throw new ArgumentOutOfRangeException("days", value, "day is out of range");
}
}
}
}

You can use DateTime.Parse/TryParse or DateTime.ParseExact/TryParseExact:
string line = Console.ReadLine();
DateTime dt;
bool validDate = DateTime.TryParseExact(line,"dd/MM/yyyy", DateTimeFormatInfo.InvariantInfo,DateTimeStyles.None, out dt);
if(validDate)
Console.WriteLine(dt.ToLongDateString()); // now correctly initialized
With this format also DateTime.Parse/DateTime.TryParse works:
validDate = DateTime.TryParse(line, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.None, out dt);
I use DateTimeFormatInfo.InvariantInfo to prevent that your local date separator is used instead of /(in case it's different).
Once it is parsed to DateTime it's trivial to create your Date instance:
Date d = new Date(dt.Day, dt.Month, dt.Year);

If you do NOT want to use DateTime.(Try)Parse, you can add a parse method with a Regex in your Date class:
public static Date ParseFromString(string s)
{
//string s = "24/12/2015";
Regex r = new Regex(#"(\d+)[\/](\d+)[\/](\d+)");
Match m = r.Match(s);
if (m.Success)
{
return new Date(m.Groups[1], m.Groups[2], m.Groups[3]);
}
else
{
// throw exception
}
}

You can't parse dd/MM/yyyy formatted string to int because it is not a valid string.
You need to parse it to DateTime first and you can use it's properties to get it's day, month and year as a numbers.
For example;
Console.WriteLine("please enter date as dd/MM/yyyy");
DateTime dt = DateTime.ParseExact(Console.ReadLine(), "dd/MM/yyyy",
CultureInfo.InvariantCulture);
int day = dt.Day;
int month = dt.Month;
int year = dt.Year;
Or you can use TryParseExact if you don't wanna throw exception if input is not dd/MM/yyyy format.
I am not wanting to use the preset DateTime class but I am using my
own "Date" class
If so, after you parse it, you can create your Date class instance with Date(int day, int month, int year) constructor based on this dt value as;
Date myDt = new Date(dt.Day, dt.Month, dt.Year);

Related

C# Converting values passed as arguments to variables

I am having trouble understanding the relationship between variables and arguments passed to a method. The program below is supposed to take three integers from the main method (M, D, Y) and use various methods to validate if it is a valid date. This includes ensuring the year is between 1900 and 2100, as well as making sure the month is 1-12, and the day is within that month's range of days (including Feb 29th on leap years). If the date from the main method is not valid, the program should say so and print the default date of 1/1/1900. The code below always prints the default no matter what arguments are provided. I believe that this is because there is an issue with how I am using either the variables M, D, Y or the variables Month, Day, Year. This program is for an assignment in which I have to use all methods and constructors in the code below. I am unsure how to have the arguments M, D, Y get turned into the variables Month, Day, and Year, so they can be printed by the ShowDate method which was provided for me.
class Date
{
private int Month;
private int Day;
private int Year;
// Sets date to 1/1/1900
public Date()
{
Month = 1;
Day = 1;
Year = 1900;
}
public Date(int M, int D, int Y)
{
SetDate(M, D, Y);
}
public Boolean SetDate(int M, int D, int Y)
{
if (ValidateDate(M, D, Y))
{
Month = M;
Day = D;
Year = Y;
return true;
}
else
{
Console.WriteLine("Invalide date");
SetDefaultDate();
return false;
}
}
private void SetDefaultDate()
{
Month = 1;
Day = 1;
Year = 1900;
}
// Determines if date is valid.
public Boolean ValidateDate(int M, int D, int Y)
{
ValidateMonth();
ValidateDay();
ValidateYear();
if (ValidateMonth() && ValidateDay() && ValidateYear())
{
ShowDate();
return true;
}
else
{
return false;
}
}
// Determines if month is valid.
public Boolean ValidateMonth()
{
if (Month >= 1 && Month <= 12)
{
return true;
}
else
{
return false;
}
}
// Determines if year is valid.
public Boolean ValidateYear()
{
if(Year >= 1900 && Year <= 2100)
{
return true;
}
else
{
return false;
}
}
// Determines if day is valid
public Boolean ValidateDay()
{
IsLeapYear();
if(Month == 1 || Month == 3 || Month == 5 || Month == 7 || Month == 8 || Month == 10 || Month == 12)
{
if (Day >= 1 && Day <= 31)
{
return true;
}
else
{
return false;
}
}
else if (Month == 4 || Month == 6 || Month == 9 || Month == 11)
{
if (Day >= 1 && Day <= 30)
{
return true;
}
else
{
return false;
}
}
else if (Month == 2 && IsLeapYear())
{
if (Day >= 1 && Day <= 29)
{
return true;
}
else
{
return false;
}
}
else if (Month == 2 && !IsLeapYear())
{
if (Day >= 1 && Day <= 28)
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
// Determine if year is a leap year
public Boolean IsLeapYear()
{
if ((Year % 4 == 0 && Year % 100 != 0) || (Year % 400 == 0))
{
return true;
}
else
{
return false;
}
}
// Print date to screen in format M/D/Y
public void DisplayDate()
{
Console.WriteLine(ShowDate());
}
public String ShowDate()
{
StringBuilder myStringBuilder = new StringBuilder();
myStringBuilder.AppendFormat("{0} / {1} / {2}", Month, Day, Year);
Console.WriteLine("{0}", myStringBuilder);
return (myStringBuilder.ToString());
}
static void Main(string[] args)
{
Date NewDate = new Date();
NewDate.SetDate(11,11,2011);
Console.ReadLine();
}
}
You never assign M, D or Y to your Month, Day and Year fields, so you are checking against your default values, which will all be zero by default. You could assign M, D and Y to their corresponding intended variables, but then you wouldn't be validating the input, just validating your fields. Instead you could have your methods accept parameters and check what you pass to it:
public Boolean ValidateMonth(int month)
{
if (month >= 1 && month <= 12)
{
return true;
}
else
{
return false;
}
}
And then when you call it
ValidateMonth(M);
And then you can do the same thing for the other two methods.
Also in your ValidateDate() method you have three useless calls to ValidateMonth(), ValidateDay() and ValidateYear(). You call each of these methods twice. (Once in the beginning, and then again in the if statement.) You can remove these:
public Boolean ValidateDate(int M, int D, int Y)
{
//Remove these:
//ValidateMonth();
//ValidateDay();
//ValidateYear();
if (ValidateMonth() && ValidateDay() && ValidateYear())
{
ShowDate();
return true;
}
else
{
return false;
}
}
Your constructor should initialize the class with the values given. Currently your default constructor initializes M, D, and Y but the constructor that takes arguments does not.
You can address this by changing the constructors to be more like this:
public Date() : this(1,1,1900)
{
}
public Date(int M, int D, int Y)
{
Month = M;
Day = D;
Year = Y;
}
Once the class is initialized, it's just a question of exposing a property or method to validate the values that are already held in the class. You shouldn't need to pass the month, day, and year into a method again, since they're already set. So the validate method might look like this:
public bool IsValid
{
get
{
return ValidateDay() && ValidateMonth() && ValidateYear();
}
}
And in your main program:
Date newDate = new Date(11,11,2011);
if (newDate.IsValid)
{
Console.WriteLine("Date is valid.");
}
else
{
Console.WriteLine("Date is not valid.");
}

How do I output the date of all Mondays this year?

I'm trying to output the dates of all Mondays this year, but my if element won't work with the conditions I'm giving it.
This is my code:
static void Main(string[] args)
{
var dagEtt = new DateTime(DateTime.Now.Year, 1, 1);
while (dagEtt <= DateTime.MaxValue)
{
if (dagEtt == DayOfWeek.Monday)
Console.WriteLine(dagEtt);
dagEtt = dagEtt.AddDays(1);
}
}
I changed your code a little bit
var start = new DateTime(DateTime.UtcNow.Year, 1, 1);
var end = start.AddYears(1);
while (start < end)
{
if (start.DayOfWeek == DayOfWeek.Monday)
{
Console.WriteLine(start);
start = start.AddDays(7);
}
else
start = start.AddDays(1);
}
You can calculate the first Monday of the year using the % operator. This greatly simplifies your loop.
static void Main(string[] args)
{
int year = DateTime.Now.Year;
DateTime startDate = FirstMonday(year);
while (startDate.Year == year)
{
Console.WriteLine(startDate);
startDate = startDate.AddDays(7);
}
}
https://stackoverflow.com/a/5665161/3194005
public static DateTime FirstMonday(int year)
{
var firstDay = new DateTime(year, 1, 1);
return new DateTime(year, 1, (8 - (int)firstDay.DayOfWeek) % 7 + 1);
}

Same code one runs other not

Struggling to find the reason why the same code behave differently. The answer provided does indeed run, but when I type the same code from the solution manual, I got an ArgumentOutOfRangeException. I just cannot see where my problem lies.
Code from solution manual, class Date:
// Exercise 10.6 Solution: Date.cs
// Date class declaration.
using System;
public class Date
{
private int month; // 1-12
private int day; // 1-31 based on month
private int year; // >0
private static readonly int[] DAYSPERMONTH =
{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
// constructor: use property Month to confirm proper value for month;
// use property Day to confirm proper value for day
public Date(int theDay, int theMonth, int theYear )
{
Month = theMonth; // validate month
Year = theYear; // validate year
Day = theDay; // validate day
Console.WriteLine( "Date object constructor for date {0}", this );
} // end Date constructor
// property that gets and sets the year
public int Year
{
get
{
return year;
} // end get
private set
{
year = CheckYear( value );
} // end set
} // end property year
// property that gets and sets the month
public int Month
{
get
{
return month;
} // end get
private set // make writing inaccessible outside the class
{
month = CheckMonth( value );
} // end set
} // end property Month
// property that gets and sets the day
public int Day
{
get
{
return day;
} // end get
private set // make writing inaccessible outside the class
{
day = CheckDay( value );
} // end set
} // end property Day
// increment the day and check if doing so will change the month
public void NextDay()
{
if ( !endOfMonth() )
++Day;
else
{
Day = 1;
NextMonth();
}
} // end method NextDay
// increment the month and check if doing so will change the year
public void NextMonth()
{
if ( Month < 12 )
++Month;
else
{
Month = 1;
++Year;
}
} // end method NextMonth
// return a string of the form month/day/year
public override string ToString()
{
return string.Format($"{Day:D2}/{Month:D2}/{Year}");
} // end method ToString
// utility method to confirm proper year value
private int CheckYear( int testYear )
{
if ( testYear > 0 ) // validate year
return testYear;
else // year is invalid
throw new ArgumentOutOfRangeException(
"year", testYear, "year must greater than 0" );
} // end method CheckYear
// utility method to confirm proper month value
private int CheckMonth( int testMonth )
{
if ( testMonth > 0 && testMonth <= 12 ) // validate month
return testMonth;
else // month is invalid
throw new ArgumentOutOfRangeException(
"month", testMonth, "month must be 1-12" );
} // end method CheckMonth
// utility method to confirm proper day value based on month and year
private int CheckDay( int testDay )
{
// Check if day in range for month
if ( testDay > 0 && testDay <= DAYSPERMONTH[ Month ] )
return testDay;
// Check for leap year
if ( testDay == 29 && leapYear() )
return testDay;
throw new ArgumentOutOfRangeException(
"day", testDay, "day out of range for current month/year" );
} // end method CheckDay
// check for end of month
private bool endOfMonth()
{
if ( leapYear() && Month == 2 && Day == 29 )
return true;
else
return Day == DAYSPERMONTH[ Month ];
} // end method endOfMonth
private bool leapYear()
{
return Month == 2 && ( Year % 400 == 0 ||
( Year % 4 == 0 && Year % 100 != 0 ) );
} // end method leapYear
} // end class Date
Code from solution manual, class DateTest:
// Exercise 10.6 Solution: DateTest
// Application tests Date class with year validation,
// NextDay and NextMonth methods.
using System;
public class DateTest
{
// method Main begins execution of C# application
public static void Main( string[] args )
{
Console.WriteLine( "Checking increment" );
Date testDate = new Date( 18, 9, 1980 );
// test incrementing of day, month and year
for ( int counter = 0; counter < 40; counter++ )
{
testDate.NextDay();
Console.WriteLine( "Incremented Date: {0}",
testDate.ToString() );
}
Console.Read();// end for
} // end Main
} // end class DateTest
My own copied code from Solution manual, class Date:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
namespace Ex_10._06
{
public class Date
{
private int day;
private int month;
private int year;
private static readonly int[] DAYSPERMONTH = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
public Date(int theDay, int theMonth, int theYear)
{
Day = theDay;
Month = theMonth;
Year = theYear;
WriteLine($"Date object constructor for date {this}");
}
public int Year
{
get
{
return year;
}
private set
{
year = CheckYear(value);
}
}
public int Month
{
get
{
return month;
}
private set
{
month = CheckMonth(value);
}
}
public int Day
{
get
{
return day;
}
private set
{
day = CheckDay(value);
}
}
public void NextDay()
{
if (!endOfMonth())
++Day;
else
{
Day = 1;
NextMonth();
}
}
public void NextMonth()
{
if (Month < 12)
++Month;
else
{
Month = 1;
++Year;
}
}
public override string ToString()
{
return string.Format("{0}/{1}/{2}", Day, Month, Year);
}
private int CheckYear(int testYear)
{
if (testYear >= 0)
return testYear;
else
throw new ArgumentOutOfRangeException("Year", testYear, "Year must be equal or greater than 0");
}
private int CheckMonth(int testMonth)
{
if (testMonth > 0 && testMonth <= 12)
return testMonth;
else
throw new ArgumentOutOfRangeException("Month", testMonth, "Month must be 1-12");
}
private int CheckDay(int testDay)
{
if (testDay > 0 && testDay <= DAYSPERMONTH[Month])
return testDay;
if (testDay == 29 && leapYear())
return testDay;
throw new ArgumentOutOfRangeException("Day", testDay, "Day out of range for current month/year");
}
private bool endOfMonth()
{
if (leapYear() && Month == 2 && Day == 29)
return true;
else
return Day == DAYSPERMONTH[Month];
}
private bool leapYear()
{
return Month == 2 && (Year % 400 == 0 || (Year % 4 == 0 && Year % 100 != 0));
}
}
}
My own code copied from solution manual, class DateTest:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
namespace Ex_10._06
{
public class DateTest
{
public static void Main(string[] args)
{
WriteLine("Checking increment");
Date d1 = new Date(18, 9, 1979);
for (int i = 0; i < 100; i++)
{
d1.NextDay();
WriteLine($"Incremented Date: {d1.ToString()}");
}
Read();
}
}
}
True to be told, I am still learning. Maybe there is something I have overlooked, but I have even copied the style how to indent, still it produces an ArgumentOutOfRangeException, while the original code does run. Thanks in advance for your time.
See image call stack:
Call Stack
The error you are facing is because you switched the order in which properties are given their values in the constructor. When you declare a new date, you do CheckDay before anything else, which works out whether the day is valid in the given month, but it is done before the month is specified so that's your exception.
In the original code
Month = theMonth; // validate month
Year = theYear; // validate year
Day = theDay; // validate day
In the your code
Day = theDay;
Month = theMonth;
Year = theYear;
This causes an error because a month needs to be defined before the date, as it checks the array using the current month as an index.
Specifically, in CheckDay(), this code is run
if (testDay > 0 && testDay <= DAYSPERMONTH[Month])
return testDay;
Which, when Month = null evaluates to this
if (testDay > 0 && testDay <= DAYSPERMONTH[null])

How to determine if given date falls in next week/month

for example I have to choose in datetimepicker May 16,2014 the messge box will pop out "This Week" and if I choose in datetimepicker May 20,2014 it will pop out "Next Week" and also June 20,2014 will pop out "Next Month".
I tried this..
System.Globalization.CultureInfo ci = System.Threading.Thread.CurrentThread.CurrentCulture;
DayOfWeek firstDayOfWeek = ci.DateTimeFormat.FirstDayOfWeek;
int offset = firstDayOfWeek - DateTime.Now.DayOfWeek;
DayOfWeek lastDayOfWeek = DateTime.Now.AddDays(offset).AddDays(6).DayOfWeek;
DateTime nextmonth = DateTime.Now.AddMonths(1);
DateTime input = DateTime.Now.AddDays(1);
input = dateTimePicker1.Value;
DateTime startOfWeek = DateTime.Today;
while (startOfWeek.DayOfWeek != firstDayOfWeek)
startOfWeek = startOfWeek.AddDays(-1);
DateTime endOfWeek = DateTime.Now;
while (endOfWeek.DayOfWeek != lastDayOfWeek)
endOfWeek = endOfWeek.AddDays(1);
bool thisWeek = input >= startOfWeek && input <= endOfWeek;
bool Thismonth = input == startOfWeek && input < endOfWeek;
bool nextMonth = input == nextmonth;
if (thisWeek == true)
{
label1.Text = "This Week";
}
else if (thisWeek == false)
{
label1.Text = "Next Week";
}
else if (nextMonth == true)
{
label1.Text = "Next Month";
}
Not too much of a problem to do. C# provides lots of Date Time Functions, but not "Is this week" although you could write an extension method for this.
System.Globalization.CultureInfo ci = System.Threading.Thread.CurrentThread.CurrentCulture;
DayOfWeek firstDayOfWeek = ci.DateTimeFormat.FirstDayOfWeek;
int offset = firstDayOfWeek - DateTime.Now.DayOfWeek;
DayOfWeek lastDayOfWeek = DateTime.Now.AddDays(offset).AddDays(6).DayOfWeek;
DateTime input = DateTime.Now.AddDays(1);
DateTime startOfWeek = DateTime.Today;
while (startOfWeek.DayOfWeek != firstDayOfWeek)
startOfWeek = startOfWeek.AddDays(-1);
DateTime endOfWeek = DateTime.Now;
while (endOfWeek.DayOfWeek != lastDayOfWeek)
endOfWeek = endOfWeek.AddDays(1);
Console.WriteLine("Week starts: " + startOfWeek);
Console.WriteLine("Week ends: " + endOfWeek);
Console.WriteLine("Input was: " + input);
Console.Write("Is input this week? ");
bool thisWeek = input >= startOfWeek && input <= endOfWeek;
Console.WriteLine(thisWeek);

Calculate DateTime for upcoming day of week

This is the code I have at the moment:
String getDayRequested;
public void setDay(String getDayFromForm1)
{
getDayRequested = getDayFromForm1;
{
if (getDayRequested.Contains("today"))
{
getDayRequested = DateTime.Today.DayOfWeek.ToString();
}
else if (getDayRequested.Contains("tomorrow"))
{
getDayRequested = DateTime.Today.AddDays(1).DayOfWeek.ToString();
}
}
This checks my TextBox.Text string from Form1, and checks to see if the text "today" or "tomorrow" is in it.
Can anyone help me in the right direction of how to check the string for information asked about upcoming days; ie: "What will be the date this saturday", and add the appropriate number of days depending on what the day is when asked.
UPDATE
Using the code in the accepted answer, I used the following in my above else if statement to complete what I was after:
else if (getDayRequested.Contains("monday"))
{
getDayRequested = GetFutureDay(DateTime.Now, DayOfWeek.Monday).ToString("dd");
}
This handy little method will return a future day of the week.
public DateTime GetFutureDay(DateTime start, DayOfWeek day)
{
int daysToAdd = (day - start.DayOfWeek + 7) % 7;
return start.AddDays(daysToAdd);
}
It would be called like:
var day = (DayOfWeek)Enum.Parse(typeof(DayOfWeek), getDayFromForm1);
var getDayRequested = GetFutureDay(DateTime.Now, day);
Consider the following snippet of code...
DateTime date;
public void setDay(String day)
{
DayOfWeek futureDay = (DayOfWeek)Enum.Parse(typeof(DayOfWeek), day);
int futureDayValue = (int)futureDay;
int currentDayValue = (int)DateTime.Now.DayOfWeek;
int dayDiff = futureDayValue - currentDayValue;
if (dayDiff > 0)
{
date = DateTime.Now.AddDays(dayDiff);
}
else
{
date = DateTime.Now.AddDays(dayDiff + 7);
}
}
Good Luck!

Categories