I have created my own DateTime class and it seems to be working. I was just wondering how can I print errors within my console for my ArgumentOutOfRangeExceptions? I am unsure how to do this so I would like some help.
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("\t\t\t\t\t\tNextDate Application\n\t\t\t\t\t-------------------------------------");
Console.WriteLine("please enter date as dd/MM/yyyy");
int day;
int month;
int year;
string[] read = Console.ReadLine().Split('/');
day = int.Parse(read[0]);
month = int.Parse(read[1]);
year = int.Parse(read[2]);
Date date = new Date(day, month, year);
Console.WriteLine("{0}/{1}/{2}", date.Day, date.Month, date.Year);
Console.ReadLine();
}
class Date
{
private int _month; // 1-12
private int _day; // 1-31 depending on month
private int _year;
public Date(int day, int month, int year)
{
Month = month;
Day = day;
Year = year;
}
public int Year
{
get { return _year; }
set
{
if (value >= 1820 && value <= 2020)
_year = value;
else
throw new ArgumentOutOfRangeException("year", value, "year out of range");
}
}
public 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 Day
{
get { return _day; }
set
{
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("Day", value, "Day is out of range");
}
}
}
}
}
simply catch the exceptions you throw
try
{
Date date = new Date(day, month, year);
}
catch(ArgumentOutOfRangeException exc)
{
Console.WriteLine(exc.Message);
}
also note that you have to handle user input: you are assuming that he will insert a string such "NN/NN/NNNN". What if he insert "NN/NN"? or "this/will/crash"?
Given your current design, you could do it like this:
try
{
Date date = new Date(day, month, year);
Console.WriteLine("{0}/{1}/{2}", date.Day, date.Month, date.Year);
}
catch (ArgumentOutOfRangeException ex)
{
Console.WriteLine(ex.Message);
}
Note that reinventing the wheel isn't necessary (unless you're intentionally experimenting)... using the correct built-in .NET constructs (like TryParseExact instead of throwing and catching exceptions) will save you a lot of trouble:
Console.WriteLine("please enter date as dd/MM/yyyy");
DateTime date;
if (DateTime.TryParseExact(Console.ReadLine(), "dd/MM/yyyy", null, DateTimeStyles.None, out date))
{
Console.WriteLine("Correct date: {0}", date.ToString("dd/MM/yyyy"));
}
else
{
Console.WriteLine("Invalid date!");
}
Console.ReadLine();
Related
I am trying to call the GetMonths() method during the Row_Inserting() method but it shows me an error. Also, how do I copy the value of this method to a variable named Total_Pay?
public override bool Row_Inserting(OrderedDictionary rsold, ref OrderedDictionary rsnew)
{
GetMonths(FROM_DATE, TO_DATE);
return true;
}
public int GetMonths(DateTime FROM_DATE, DateTime TO_DATE)
{
if (FROM_DATE > TO_DATE)
{
throw new Exception("Start Date is greater than the End Date");
}
int months = ((TO_DATE.Year * 12) + TO_DATE.Month) - ((FROM_DATE.Year * 12) + FROM_DATE.Month);
if (TO_DATE.Day >= FROM_DATE.Day)
{
months++;
}
return months;
}
Hope this helps..
public override bool Row_Inserting(OrderedDictionary rsold, ref OrderedDictionary rsnew)
{
int Total_Pay;
DateTime FROM_DATE = DateTime.Parse("02-May-2016"); //Replace with date you need
DateTime TO_DATE = DateTime.Parse("08-May-2016"); //Replace with date you need
Total_Pay = GetMonths(FROM_DATE, TO_DATE);
return true;
}
public int GetMonths(DateTime FROM_DATE, DateTime TO_DATE)
{
if (FROM_DATE > TO_DATE)
{
throw new Exception("Start Date is greater than the End Date");
}
int months = ((TO_DATE.Year * 12) + TO_DATE.Month) - ((FROM_DATE.Year * 12) + FROM_DATE.Month);
if (TO_DATE.Day >= FROM_DATE.Day)
{
months++;
}
return months;
}
And checkout this similar question Link
I have created a Date program which should return the user the date when inputted. I have not been using DateTime, as I wanted to create my own Date class instead. For some reason within my if statements my value does not seem to be working within my main for some reason. Is there any way around this problem?
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;
string[] read = Console.ReadLine().Split('/');
day = int.Parse(read[0]);
month = int.Parse(read[1]);
year = int.Parse(read[2]);
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
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 Year
{
get { return year; }
set
{
if (value > 0 && value <= 12)
month = value;
else
throw new ArgumentOutOfRangeException("year", value, "year out of range");
}
}
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 Day
{
get { return day; }
set
{
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 are using member variables, not properties as you intended
Console.WriteLine("{0}/{1}/{2}", i.Day, i.Month, i.Year);
changed the .day to .Day
Refactored your code a little bit. This way, it will do all the validations when you try setting the values. Setters can be made private, as you might only allow the user to set thing via constructor.
class Date
{
private int _month; // 1-12
private int _day; // 1-31 depending on month
private int _year;
public Date(int day, int month, int year)
{
Day = day;
Month = month;
Year = year;
}
public int Year
{
get { return _year; }
set
{
_year = value;
//Do you checks and throw exception as needed
//throw new ArgumentOutOfRangeException("year", value, "year out of range");
}
}
public 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 Day
{
get { return _day; }
set
{
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("Day", value, "Day is out of range");
}
}
}
I don't have reputation enough to comment. So I answer: Lacked the leap year in your date class.
Besides learning a new language there is no reason in C# to reinvent new Date classes.
It is one of the biggest mistakes coming from the C++ ages before an official string type was there. Everybody had its own string class. We have now about 6 in our software with code to convert between all of them.
So my advise: Don't do this and instead try to read the documentation because most of the functionality is there. If it isn't there, please create extension methods and at last resort derive oder embed the existing class.
Let's say I have a list of dates in a table. Now I want to find all rows, which is in the same week as the date provided as an argument.
Let's say I have a table with:
2014-09-11
2014-09-12
2014-09-15
And I give this function the argument 2014-09-09, it has to look from monday->sunday, and realize that 09-11 and 09-12 is part of the week, but not 09-15.
How on earth to solve this?
I have thought on making a check on year, month and weeknumber, but you cannot guarantee that month is the same...
So how do you solve a problem like this?
DxCk's comment is valid. This solution will work even if the first or last week of the year cross two different years:
Check that the first day of the week for both dates fall on the same day.
Here is the code:
private bool DatesAreInTheSameWeek(DateTime date1, DateTime date2)
{
var cal = System.Globalization.DateTimeFormatInfo.CurrentInfo.Calendar;
var d1 = date1.Date.AddDays(-1 * (int)cal.GetDayOfWeek(date1));
var d2 = date2.Date.AddDays(-1 * (int)cal.GetDayOfWeek(date2));
return d1 == d2;
}
why not?
bool AreFallingInSameWeek(DateTime date1, DateTime date2)
{
return date1.AddDays(-(int)date1.DayOfWeek) == date2.AddDays(-(int)date2.DayOfWeek);
}
if you want to use any day other than Sunday as start of the week
bool AreFallingInSameWeek(DateTime date1, DateTime date2, DayOfWeek weekStartsOn)
{
return date1.AddDays(-GetOffsetedDayofWeek(date1.DayOfWeek, (int)weekStartsOn)) == date2.AddDays(-GetOffsetedDayofWeek(date2.DayOfWeek, (int)weekStartsOn));
}
int GetOffsetedDayofWeek(DayOfWeek dayOfWeek, int offsetBy)
{
return (((int)dayOfWeek - offsetBy + 7) % 7)
}
Check the DateTime.Year and Calendar.GetWeekOfYear(DateTime, ...). No need to check for the month.
EDIT: This is wrong but I can't delete it. See #Sparrow's answer below.
Use: public virtual int GetWeekOfYear(DateTime time,CalendarWeekRule rule,DayOfWeek firstDayOfWeek) of Calendar class
My requirement was to find DOBs falling on the current week. Hope this helps with your doubt. Basically the idea behind this code is as follows:
Change the DOB to current year birthday (eg; 24-02-1988 to 24-02-2018(current year).
Add a year, if the brithday week contains both dec and jan
Get the first day of today's week.
Get last day of today's week.
check if the current year birthday falls between first day and last day of today's week.
private bool DatesAreInTheSameWeek(DateTime birthday)
{
if (birthday == DateTime.MinValue)
{
return false;
}
else
{
var birtdayWithCurrentYear = new DateTime(DateTime.Today.Year, birthday.Month, birthday.Day);
if (birthday.Month == 1 && DateTime.Today.Month != 1)
{
birtdayWithCurrentYear = birtdayWithCurrentYear.AddYears(1);
}
DateTime firstDayInWeek = DateTime.Today.Date;
while (firstDayInWeek.DayOfWeek != CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek)
firstDayInWeek = firstDayInWeek.AddDays(-1);var lastDayInWeek = firstDayInWeek.AddDays(7);
return birtdayWithCurrentYear < lastDayInWeek && birtdayWithCurrentYear >= firstDayInWeek;
}
}
Since the accepted answer contains error as #DxCK mentioned in comment, here is my solution for this:
public static class DateExtensions
{
private static void Swap<T>(ref T one, ref T two)
{
var temp = one;
one = two;
two = temp;
}
public static bool IsFromSameWeek(this DateTime first, DateTime second, DayOfWeek firstDayOfWeek = DayOfWeek.Monday)
{
// sort dates
if (first > second)
{
Swap(ref first, ref second);
}
var daysDiff = (second - first).TotalDays;
if (daysDiff >= 7)
{
return false;
}
const int TotalDaysInWeek = 7;
var adjustedDayOfWeekFirst = (int)first.DayOfWeek + (first.DayOfWeek < firstDayOfWeek ? TotalDaysInWeek : 0);
var adjustedDayOfWeekSecond = (int)second.DayOfWeek + (second.DayOfWeek < firstDayOfWeek ? TotalDaysInWeek : 0);
return adjustedDayOfWeekSecond >= adjustedDayOfWeekFirst;
}
}
Also here is link to another correct solution with slightly different approach.
Find start and end dates for the first date's week. Then check if the second date is between those two.
public static bool DateInsideOneWeek(DateTime date1, DateTime date2)
{
DayOfWeek firstDayOfWeek = System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek;
DateTime startDateOfWeek = date1.Date;
while(startDateOfWeek.DayOfWeek != firstWeekDay)
{ startDateOfWeek = startDateOfWeek.AddDays(-1d); }
DateTime endDateOfWeek = startDateOfWeek.AddDays(6d);
return date2 >= startDateOfWeek && date2 <= endDateOfWeek;
}
If you don't want to use the Calendar class you can use this function:
public static int WeekOfYear(DateTime dt)
{
int startDays = 0;
// first day of the year
DateTime firstJanuary = new DateTime(dt.Year, 1, 1);
if (firstJanuary.DayOfWeek == DayOfWeek.Tuesday)
{
startDays = 1;
}
else if (firstJanuary.DayOfWeek == DayOfWeek.Wednesday)
{
startDays = 2;
}
else if (firstJanuary.DayOfWeek == DayOfWeek.Thursday)
{
startDays = 3;
}
else if (firstJanuary.DayOfWeek == DayOfWeek.Friday)
{
startDays = 4;
}
else if (firstJanuary.DayOfWeek == DayOfWeek.Saturday)
{
startDays = 5;
}
else if (firstJanuary.DayOfWeek == DayOfWeek.Sunday)
{
startDays = 6;
}
if (DateTimeFormatInfo.CurrentInfo.FirstDayOfWeek == DayOfWeek.Sunday)
{
startDays++;
startDays = startDays % 7;
}
return ((dt.DayOfYear + startDays - 1) / 7) + 1;
}
Accepted answer doesn't work for a french calendar and when the dates are 03/10/2022 and 09/10/2022.
This worked for me :
public static partial class DateTimeExtensions
{
public static DateTime FirstDayOfWeek(this DateTime dt)
{
var culture = System.Threading.Thread.CurrentThread.CurrentCulture;
var diff = dt.DayOfWeek - culture.DateTimeFormat.FirstDayOfWeek;
if (diff < 0)
{
diff += 7;
}
return dt.AddDays(-diff).Date;
}
public static DateTime LastDayOfWeek(this DateTime dt) =>
dt.FirstDayOfWeek().AddDays(6);
public static DateTime FirstDayOfMonth(this DateTime dt) =>
new DateTime(dt.Year, dt.Month, 1);
public static DateTime LastDayOfMonth(this DateTime dt) =>
dt.FirstDayOfMonth().AddMonths(1).AddDays(-1);
public static DateTime FirstDayOfNextMonth(this DateTime dt) =>
dt.FirstDayOfMonth().AddMonths(1);
public static int GetWeeekNumber(this DateTime dt)
{
CultureInfo culture = System.Threading.Thread.CurrentThread.CurrentCulture;
Calendar myCal = culture.Calendar;
// Gets the DTFI properties required by GetWeekOfYear.
CalendarWeekRule myCWR = culture.DateTimeFormat.CalendarWeekRule;
DayOfWeek myFirstDOW = culture.DateTimeFormat.FirstDayOfWeek;
return myCal.GetWeekOfYear(dt, myCWR, myFirstDOW);
}
public static bool IsInTheSameWeek(this DateTime date1, DateTime date2)
{
return date1.GetWeeekNumber() == date2.GetWeeekNumber();
}
}
Usage :
item.Week.IsInTheSameWeek(Week)
I need a function which gives me the nth DateTime of the next Month.
For Example: I need the 4th Wednesday of next Month.
My code delivers a wrong Date:
private static DateTime FindNextDay(DayOfWeek dayOfWeek, DateTime fday, Int32 instance)
{
DateTime day = new DateTime(fday.Year, fday.Month, 1, fday.Hour, fday.Minute, fday.Second);
// DateTime day is in this Example= 2014-08.01 11.00 AM
if (instance == 2)
{
day = day.AddDays(7);
}
else if (instance == 3)
{
day = day.AddDays(14);
}
else if (instance == 4) //if the 4th week is requested
{
day = day.AddDays(28); // i add 28 days
}
while (day.DayOfWeek != dayOfWeek)
{
day = day.AddDays(1); // and search the wednesday and return it back
}
return day;
}
Could you show me a better solution?
Something like this..
Get the first day of the next month, keep a count of the number of wednesdays you've encountered adding to it when you find one. Return when the count is 4.
private static DateTime GetFourthWednesday()
{
DateTime firstOfMonth = new DateTime(DateTime.Now.AddMonths(1).Year, DateTime.Now.AddMonths(1).Month, 1);
int count = 0;
while (count < 4)
{
if (firstOfMonth.DayOfWeek == DayOfWeek.Wednesday)
{
count++;
}
if (count == 4)
{
return firstOfMonth;
}
firstOfMonth = firstOfMonth.AddDays(1);
}
return firstOfMonth;
}
Gives 27/08/2014 if run today
Change the last else if to:
else if (instance == 4) //if the 4th week is requested
{
day = day.AddDays(21); // i add 28 days
}
You should add 21 days not 28.
Since because I'm too lazy, I wrote my code like;
DateTime firstDayOfNextMonth = new DateTime(2014, DateTime.Now.Month + 1, 1);
int count = 0;
if (firstDayOfNextMonth.DayOfWeek == DayOfWeek.Wednesday)
count = 1;
while (count != 4)
{
firstDayOfNextMonth = firstDayOfNextMonth.AddDays(1);
if (firstDayOfNextMonth.DayOfWeek == DayOfWeek.Wednesday)
count++;
}
Console.WriteLine(firstDayOfNextMonth);
Basicly, I check if the first day of next month is Wednesday or not, then I iterate my DateTime to found 4. Wednesday in next month.
It is working for today and it prints 27.08.2014 which is fourth Wednesday of next month.
You can write an extension method like;
public static class DateTimeExtensions
{
public static void FindInstanceNextMonth(DateTime Now, DayOfWeek day, int instance)
{
DateTime firstDayOfNextMonth = new DateTime(Now.Year, Now.Month + 1, 1);
int count = 0;
if (firstDayOfNextMonth.DayOfWeek == day)
count = 1;
while (count != instance)
{
firstDayOfNextMonth = firstDayOfNextMonth.AddDays(1);
if (firstDayOfNextMonth.DayOfWeek == day)
count++;
}
Console.WriteLine(firstDayOfNextMonth);
}
}
And call it as;
DateTimeExtensions.FindInstanceNextMonth(DateTime.Now,
DayOfWeek.Wednesday,
4);
In my project I am working on patient flow where if the patient only a couple days old then my UI is just showing 0 year old instead of, for example 2 days old or 6 months old.
I want to include this logic to calculate age in months and days of patient.
below is the C# function i am using for calculating age of patient:
public int CalculatedAge
{
get
{
if (Patient.DateOfBirth == null && !Patient.Age.HasValue)
return 0;
else if (Patient.DateOfBirth == null && Patient.Age != null && Patient.Age.HasValue)
return Patient.Age.Value;
else if (Patient.DateOfBirth != null)
return DateTime.Now.ToUniversalTime().Year - Patient.DateOfBirth.Value.Year;
return 0;
}
}
You can create new entities.
enum AgeUnits
{
Days,
Months,
Years
}
class Age
{
public int Value { get; private set; }
public AgeUnits Units { get; private set; }
public Age(int value, AgeUnits ageUnits)
{
Value = value;
Units = ageUnits;
}
}
Then you can use Age as type of CalculatedAge property.
public Age CalculatedAge
{
get
{
if (Patient.DateOfBirth.HasValue)
{
DateTime bday = Patient.DateOfBirth.Value;
DateTime now = DateTime.UtcNow;
if (bday.AddYears(1) < now)
{
int years = now.Year - bday.year;
if (bday > now.AddYears(-years))
years--;
return new Age(years, AgeUnits.Years);
}
else if (bday.AddMonths(1) < now)
{
int months = (now.Months - bday.Months + 12) % 12;
if (bday > now.AddMonths(-months))
months--;
return new Age(months, AgeUnits.Months);
}
else
{
int days = (now - bday).Days;
return new Age(days, AgeUnits.Days);
}
}
else
{
if (Patient.Age.HasValue)
return new Age(Patient.Age.Value, AgeUnits.Years);
else
return null;
}
}
}
public Age CalculatedAge
{
get
{
if (Patient.DateOfBirth == null && Patient.Age != null && Patient.Age.HasValue)
return new Age(Patient.Age.Value);
else if (Patient.DateOfBirth != null)
{
DateTime now = DateTime.UtcNow;
TimeSpan tsAge = now - Patient.DateOfBirth;
DateTime age = new DateTime(tsAge.Ticks);
return new Age(age.Year - 1, age.Month - 1, age.Day - 1);
}
return new Age(0);
}
}
And this is the Age struct:
struct Age
{
public int Years, Months, Days; //It's a small struct, properties aren't necessary
public Age(int years, int months = 0, int days = 0) { this.Years = years; this.Months = months; this.Days = days; }
}
Obviously you can just check the values in with IF statements but a struct for this purpose is cleaner in my opinion.
return new Age(age.Year - 1, age.Month - 1, age.Day - 1); This part is due to the fact that the MinValue of a DateTime object is 01/01/0001 so you need to substract that to get the real age.