I want to allow the user to enter the year in blank but I don´t know where to put \s\s\s\s in the following expression.
Here is an example of what I need to do: if the user inserts 03-07-_____ the program must be executed every 3Th of July of each year(and it proceeds the same way if the user inserts blank date, month or year or twoo of this three)
System.Text.RegularExpressions.Regex rdate =
new System.Text.RegularExpressions.Regex(#"^((((0?[1-9]|[12]\d|3[01]|\s\s|\s\d)[\-](0?[13578]|1[02]|\s\s)[\-]((1[6-9]|[2-9]\d)?\d{2}))|((0?[1-9]|[12]\d|30)[\-](0?[13456789]|1[012])[\-]((1[6-9]|[2-9]\d)?\d{2}))|((0?[1-9]|1\d|2[0-8])[\-]0?2[\-]((1[6-9]|[2-9]\d)?\d{2}))|(29[\-]0?2[\-]((1[6-9]|[2-9]\d)?(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00)|00)))|(((0[1-9]|[12]\d|3[01])(0[13578]|1[02])((1[6-9]|[2-9]\d)?\d{2}))|((0[1-9]|[12]\d|30)(0[13456789]|1[012])((1[6-9]|[2-9]\d)?\d{2}))|((0[1-9]|1\d|2[0-8])02((1[6-9]|[2-9]\d)?\d{2}))|(2902((1[6-9]|[2-9]\d)?(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00)|00))))$");
Could someone help me?(this expression validates even a leap year)
Here is what You asked for
System.Text.RegularExpressions.Regex rdate =
new System.Text.RegularExpressions.Regex(#"^((((0?[1-9]|[12]\d|3[01]|\s\s|\s\d)[\-](0?[13578]|1[02]|\s\s)[\-]((1[6-9]|[2-9]\d)?\d{2}|\s\s\s\s))|((0?[1-9]|[12]\d|30)[\-](0?[13456789]|1[012])[\-]((1[6-9]|[2-9]\d)?\d{2}|\s\s\s\s))|((0?[1-9]|1\d|2[0-8])[\-]0?2[\-]((1[6-9]|[2-9]\d)?\d{2}|\s\s\s\s))|(29[\-]0?2[\-]((1[6-9]|[2-9]\d)?(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00)|00|\s\s\s\s)))|(((0[1-9]|[12]\d|3[01])(0[13578]|1[02])((1[6-9]|[2-9]\d)?\d{2}))|((0[1-9]|[12]\d|30)(0[13456789]|1[012])((1[6-9]|[2-9]\d)?\d{2}))|((0[1-9]|1\d|2[0-8])02((1[6-9]|[2-9]\d)?\d{2}))|(2902((1[6-9]|[2-9]\d)?(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00)|00))))$");
But I am not sure it is what You really want. The regex was already patched, I continued the way. But not only it is maintenance nightmare, it behaves strange. It accepts empty day, but only when month is january, march, may... or empty. Less lines of code is not always better. I would suggest to rewrite it completely. Something simmilar to this:
protected DateTime? getDateTimeFromParts(string day, string month, string year)
{
DateTime now = DateTime.Now;
int iyear;
if (string.IsNullOrWhiteSpace(year))
{
iyear = now.Year;
}
else
{
iyear = int.Parse(year);
if (iyear >= 0 && iyear < 100) { iyear += 2000; }
}
int imonth;
if (string.IsNullOrWhiteSpace(month))
{
imonth = now.Month;
}
else
{
imonth = int.Parse(month);
}
int iday;
if (string.IsNullOrWhiteSpace(day))
{
iday = now.Day;
}
else
{
iday = int.Parse(day);
}
if (iyear <= DateTime.MaxValue.Year && iyear >= DateTime.MinValue.Year)
{
if (imonth >= 1 && imonth <= 12)
{
if (DateTime.DaysInMonth(iyear, imonth) >= iday && iday >= 1)
return new DateTime(iyear, imonth, iday);
}
}
return null;
}
protected DateTime? getDateTime(string dateStr)
{
Regex r = new Regex(#"^(\d\d)(\d\d)((\d\d)?\d\d)$");
Match m = r.Match(dateStr);
if (m.Success)
{
return getDateTimeFromParts(m.Groups[1].Value, m.Groups[2].Value, m.Groups[3].Value);
}
r = new Regex(#"^(\d?\d|\s\d|\s\s)[-](\d?\d|\s\s)[-]((\d\d)?\d\d|\s\s\s\s)$");
m = r.Match(dateStr);
if (m.Success)
{
return getDateTimeFromParts(m.Groups[1].Value, m.Groups[2].Value, m.Groups[3].Value);
}
return null;
}
Related
Hi I am using C# web app on visual studio.
I have written code to be able to distinguish if the time is between 6am-2pm - 2pm-10pm and 10pm - 6am...
The code runs like a dream for the 6-2 - 2-10 times but for the 10pm - 6am.. the code runs fine until midnight and then it just resets my counter to 0 and stays at 0 until 6am.. I can't get my head around why this is doing.. Does anybody have a solution..
public DateTime Shiftstart { get; set; }
public DateTime Shiftend { get; set; }
public string Itemseriesmaster { get; set; }
public string SeriesMasterId { get; set; }
public void CalcShiftPeriod() //constructor
{
DateTime now = DateTime.Now; //date time now
int currentHour = now.Hour; //hour now
int shiftHourStart;
if (currentHour >= 6 && currentHour <= 13)
{
shiftHourStart = 6;
}
else if (currentHour >= 14 && currentHour <= 21)
{
shiftHourStart = 14;
}
else
{
shiftHourStart = 22;
}
Shiftstart = now.Date.AddHours(shiftHourStart);
Shiftend = Shiftstart.AddHours(7);
Shiftend = Shiftend.AddMinutes(59);
Shiftend = Shiftend.AddSeconds(59);
}
The code is calculating total units packed and is working fine, and resets after the given time on both the 6-2 and 2 - 10 shifts..
Until it gets to the 10pm - 6am and then just completely stops at midnight.
BizManager biz = new BizManager();
DataTable dt = new DataTable();
if (DDLProduct.SelectedValue.Equals("G120C-2") || DDLProduct.SelectedValue.Equals("G120 PM240-2") )
{
RefreshMainGridTht(selectedProduct, shiftStart, shiftEnd
);
}
dt = biz.GetPacktstatisticsForShift(shiftStart, shiftEnd, selectedProduct);
GridView1.DataSource = dt.DefaultView;
GridView1.DataBind();
int sumActual = 0;
int sumTarget = 0;
biz.CalculatePackingTotals(dt, out sumActual, out sumTarget);
LabelTotal.Text = sumActual.ToString();
DateTime dtmNow = DateTime.Now;
TimeSpan tsIntoShift = dtmNow - shiftStart;
TimeSpan tsTotalShift = shiftEnd - shiftStart;
double p = tsIntoShift.TotalMinutes / tsTotalShift.TotalMinutes;
int adjustedTarget = Convert.ToInt32(sumTarget * p);
if (sumActual > sumTarget)
{
LabelTotal.ForeColor = Color.Lime;
}
else
{
LabelTotal.ForeColor = Color.Red;
}
}
catch (Exception ex)
{
ErrMsg = App.HandleError(MethodBase.GetCurrentMethod(), ex, string.Empty);
You have to distinguish between currentHour from 0 to 5 and currentHour from 22 to 23.
For example, consider currentHour is 1. Your calculation says that the shift starts at 22:00 of the current day (now.Date.AddHours(22)), which is obviously wrong because the shift already started at 22:00 of the previous day.
So from currentHour 0 to 5 you have to subtract a day from your Shiftstart.
One possible way to do that would be to set shiftHourStart to -2 for currentHour between 0 and 5.
if (currentHour < 6)
{
shiftHourStart = -2;
}
else if (currentHour >= 6 && currentHour <= 13)
{
shiftHourStart = 6;
}
else if (currentHour >= 14 && currentHour <= 21)
{
shiftHourStart = 14;
}
else
{
shiftHourStart = 22;
}
The error lies in adding the hours to the current day...
Shiftstart = now.Date.AddHours(shiftHourStart);
At 23:59 you are adding 22 hours to "2018-11-06".
One minute passes...
At 00:00 you are adding 22 hours to "2018-11-07".
That means your start time moves 24 hours over the course of that one minute.
You could distinguish this scenario as part of your if-statement. See the comments a) and b) below.
int currentHour = now.Hour;
DateTime date = now.Date; // a) This is today in most cases...
int shiftHourStart;
if (currentHour >= 6 && currentHour <= 13)
{
shiftHourStart = 6;
}
else if (currentHour >= 14 && currentHour <= 21)
{
shiftHourStart = 14;
}
else if (currentHour >= 22)
{
shiftHourStart = 22;
}
else
{
// midnight to 6am
date = date.AddDays(-1); // b) But not in this case
shiftHourStart = 22;
}
First store your time in a TimeSpan this will give you more flexibility if tomorrow shift start and ends at 30min. Then store those Timespan in a class that represent the time frame. And if you have a list of them make it a List. It will help reading and maintaining your code. For now it's a brunch of magic numbers.
To check if a time is in a Range, I used :
public static bool IsBetween(TimeSpan time, TimeSpan start, TimeSpan end)
=> (start <= end) ? time >= start && time <= end : time >= start || time <= end;
internal void TestMethod()
{
var timeSlots = new[] {
new TimeFrame { start= new TimeSpan(6,0,0) , end = new TimeSpan(13,0,0) },
new TimeFrame { start= new TimeSpan(14,0,0) , end = new TimeSpan(21,0,0) },
new TimeFrame { start= new TimeSpan(22,0,0) , end = new TimeSpan(6,0,0) }
};
var today = DateTime.Today;
var dayHours = Enumerable.Range(0, 24).Select(x => today.AddHours(x)).ToList();
foreach (var currentDateTime in dayHours)
{
var matchingRanges = timeSlots.Where(x => IsBetween(currentDateTime .TimeOfDay, x.start, x.end));
if (matchingRanges.Any())
{
var temp = matchingRanges.First();
Console.WriteLine($"-> {currentDateTime } is in range {temp.start}-{temp.end}");
Console.WriteLine($"\t ShiftHours= {temp.start}-{temp.end.Subtract(new TimeSpan(0, 0, 1))}");
}
else
{
Console.WriteLine($"no Match for {currentDateTime }");
}
}
}
As you added a comment about testing it at midnight , included a TestMethod where I create all hours of a day (from 00h to 23h) so you can easly see what going on.
I am having some trouble with constructors in a C# assignment. The first block of code below contains some of the instructions for the assignment. Essentially, as I understand it, I am to create two constructors, one for setting a default date, and another for checking a date from the user. Also, there is a SetDate method that seems to be doing the same thing. These seem redundant, yet according to the assignment instructions, both are required. I am VERY new to object-oriented programming so I am not sure how to "pass" stuff to a constructor or really how to use it and call it in the main method. The second block of code is what I have written so far. All of the date validation methods seem fine. But, I have no idea what to do with the public Date(int M, int D, int Y) constructor and the SetDate method. What should each of these be doing? Also, why am I being instructed to use integer variables M, D, Y when I am also being told to declare Month, Day, and Year above? Any insight that might aid me in understanding how to use this Constructer and how it relates and differs in function from the SetDate method would be greatly appreciated.
//Create a Date Class
//This class holds:
private int Month;
private int Day;
private int Year;
//Include the following constructors/methods. Include others/more if you
//need them.
// Sets date to 1/1/1900
public Date()
// Sets date to user’s input.
// Checks to see the date is valid
// If it isn’t valid, print message and set date to 1/1/1900
public Date(int M, int D, int Y)
// Sets date to user’s input.
// Checks to see the date is valid
// If it isn’t valid, print message and set date to 1/1/1900
public Boolean SetDate(int M, int D, int Y)ere
//******************************************************************************
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)
{
Month = M;
Day = D;
Year = Y;
}
public Boolean SetDate(int M, int D, int Y)
{
int valDate = 0;
Console.WriteLine("You will be prompted to enter three(3) numbers to represent a month, " +
"day, and year. Only dates between 1/1/1900 and 12/31/2100 are valid.");
Console.WriteLine("");
while (valDate < 1)
{
Console.WriteLine("Enter the number for the month.");
M = int.Parse(Console.ReadLine());
Console.WriteLine("");
Console.WriteLine("Enter the number for the day.");
D = int.Parse(Console.ReadLine());
Console.WriteLine("");
Console.WriteLine("Enter the number for the year.");
Y = int.Parse(Console.ReadLine());
Console.WriteLine("");
ValidateDate();
if (ValidateDate())
{
DisplayDate();
valDate++;
return true;
}
else
{
Console.WriteLine("Please enter a valid date.");
Console.WriteLine("");
Month = 1;
Day = 1;
Year = 1900;
return false;
}
}
return false;
}
// Determines if date is valid.
public Boolean ValidateDate()
{
ValidateMonth();
ValidateDay();
ValidateYear();
if (ValidateMonth() && ValidateDay() && ValidateYear())
{
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);
return (myStringBuilder.ToString());
}
static void Main(string[] args)
{
Date NewDate = new Date();
NewDate.Date();
Console.ReadLine();
}
}
It looks like you've been asked to create a method and a constructor that are doing the same thing. The simple thing to do in this case is to have the constructor call the method.
The only comment I would make about your code is that the problem statement you showed did not require the input to be gathered in the SetDate method. Given the statement it seems like the input from the user would be gathered outside your class.
I don't know what your requirements are for the failure message. That might make sense in it's own method as well.
Here is an example:
public class Date
{
private int Month;
private int Day;
private int Year;
public Date()
{
SetDefaultDate();
}
public Date(int M, int D, int Y)
{
SetDate(M, D, Y);
}
public void SetDate(int M, int D, int Y)
{
if (IsValidDate(M, D, Y))
{
Month = M;
Day = D;
Year = Y;
}
else
{
SetDefaultDate();
}
}
private bool IsValidDate(int M, int D, int Y)
{
// validation logic.. return true if all parameters result in valid date
// false if they do not. If it is an invalid date print the failure message.
return true;
}
private void SetDefaultDate()
{
Month = 1;
Day = 1;
Year = 1900;
}
}
If you want to make some real application using date then i'd suggesting taking look at the DateTime struct in System namespace. That has TryParse function which will return you true or false whether if the input was valid or not.
However it seems like you're doing some programming exercise so in that case my answer would be: It's not very good to have arguments in constructor which could lead to an invalid object - in your case invalid date. That's because once calling the constructor you will have an object in one way or another, except if you throw exception in constructor. Yet if you still want to have it like that then you need to have a property or public variable called "IsValid" in the class/struct which tells if valid date was given with constructor.
Nicer option is follow the DateTime approach - have a public static function which return valid Date object. Like this:
public bool TryParse(int m, int d, int y, out Date date)
{
// validate
// if valid then return Date object like that:
date = new Date()
{
Month = m,
Day = d,
Year = y
};
return true;
// Or like that:
date = new Date(m, d, y);
return true;
// if not valid then return null (because have to return something)
date = null;
return false;
}
I am developing application in Arabic/Dari/Pashto (for Afghanistan) using C# and also using Jalali/Persian calendar for date selection. I want to validate input date before saving into database. I am using below function for validation and passing Jalali/Persian calendar date to this function. It works perfectly when user select date something like "28/02/1393" but it throws error for date "31/02/1393". Both dates are valid Jalali/Persian date.
I think this issue is happenning because somehow application considering this date is English and there is no any 31st day in 2nd month in English calendar. Please help me to find solution for that.
static public bool ValidateParsianDate(string date)
{
bool status = true;
try
{
PersianCalendar persianCalendar = new PersianCalendar();
CultureInfo persianCulture = new CultureInfo("fa-IR");
DateTime persianDateTime = DateTime.ParseExact(date, "dd/MM/yyyy", persianCulture);
}
catch (Exception ex)
{
string msg = ex.Message;
status = false;
}
return status;
}
Thanks & Regards,
Rajeev
Use the PersianCalendar.ToDateTime(
int year,
int month,
int day,
int hour,
int minute,
int second,
int millisecond,
int era
) method.
static public bool ValidateParsianDate(string date)
{
bool status = true;
try
{
PersianCalendar persianCalendar = new PersianCalendar();
var dateParts = date.Split(new char[] { '/' }).Select(d=> int.Parse(d)).ToArray();
var date = persianCalendar.ToDateTime(dateParts[2], dateParts[1], dateParts[0], 0, 0,0,0, /*8 era of year here **/);
}
catch (Exception ex)
{
string msg = ex.Message;
status = false;
}
return status;
}
Because persianCulture.Calendar is set to GregorianCalendar by default in .NET framework and can't be changed to PersianCalendar without using the reflection. more info here
I had that problem but i used this and it work
public static bool IsValidDate(string date)
{
var regex = new Regex("^\\d{ 4 } /\\d{ 2}/\\d{ 2}$");
var arrPattern = new[] {
new Regex("^\\d{4}/\\d{2}/\\d{2}$"),
new Regex("^\\d{ 4 } /\\d{ 2}/\\d{ 1}$"),
new Regex("^\\d{ 4 } /\\d{ 1}/\\d{ 2}$"),
new Regex("^\\d{ 4 } /\\d{ 1}/\\d{ 1}$"),
new Regex("^\\d{ 2 } /\\d{ 2}/\\d{ 2}$"),
new Regex("^\\d{ 2 } /\\d{ 2}/\\d{ 1}$"),
new Regex("^\\d{ 2 } /\\d{ 1}/\\d{ 2}$"),
new Regex("^\\d{ 2 } /\\d{ 1}/\\d{ 1}")
};
const int kabise = 1387;
var year = 0;
var mounth = 0;
var day = 0; var flag = false;
foreach (var t in arrPattern)
{
if (t.IsMatch(date))
flag = true;
}
if (flag == false) return flag;
//جدا کننده تاریخ می تواند یکی از این کاراکترها باشد
var splitDate = date.Split('/','-',':');
year = Convert.ToInt32(splitDate[0]);
mounth = Convert.ToInt32(splitDate[1]);
day = Convert.ToInt32(splitDate[2]);
if (mounth > 12 || mounth <= 0)
flag = false;
else
{
if (mounth< 7)
{
if (day > 31)
{
flag = false;
}
}
if (mounth != 12) return flag;
var t = (year - kabise) % 4;
if ((year - kabise) % 4 == 0)
{
if (day >= 31)
flag = false;
}
else if (day >= 30)
flag = false;
}
return flag;
}
even if value in dow and dy are equal,it doesnt enter inside the loop to check equality
foreach (DayOfWeek dow in daysofweek)
{
foreach (day dy in cleave.WeekDays)
{
if (Mode == 1)
{
//textBoxnumofdays.Text = Convert.ToString(span.Days+2);
if (dow.Equals(dy))
{
textBoxnumofdays.Text = Convert.ToString(span.Days - 1);
}
else
{
textBoxnumofdays.Text = Convert.ToString(span.Days + 2);
}
}
else
{
//textBoxnumofdays.Text = Convert.ToString(span.Days + 1);
if (dow.Equals(dy))
{
textBoxnumofdays.Text = Convert.ToString(span.Days - 1);
}
else
{
textBoxnumofdays.Text = Convert.ToString(span.TotalDays + 1);
}
}
}
}
public void Getdays()
{
DateTime dtFrom = new DateTime(dateTimePickerfromdate.Value.Year,
dateTimePickerfromdate.Value.Month, dateTimePickerfromdate.Value.Day);
DateTime dtTo = new DateTime(dateTimePickertodate.Value.Year,
dateTimePickertodate.Value.Month, dateTimePickertodate.Value.Day);
daysofweek = new List<DayOfWeek>();
cleave = new LeaveApplication(constr);
while (dtTo != dtFrom)
{
dtFrom = dtFrom.AddDays(1);
daysofweek.Add(dtFrom.DayOfWeek);
}
}
I presume you are trying to check if its a weekday or not
foreach (DayOfWeek dow in daysofweek)
{
}
So just compare it with like dow == DayOfWeek.Sunday and accept or ignore based on your requirement.
Because for each daysofweek it will do a full cycle of cleave.WeekDays, so it will probably activate first the if part and in the next cycle the else part. What are you trying to do?
Given a date how can I add a number of days to it, but exclude weekends. For example, given 11/12/2008 (Wednesday) and adding five will result in 11/19/2008 (Wednesday) rather than 11/17/2008 (Monday).
I can think of a simple solution like looping through each day to add and checking to see if it is a weekend, but I'd like to see if there is something more elegant. I'd also be interested in any F# solution.
using Fluent DateTime https://github.com/FluentDateTime/FluentDateTime
var dateTime = DateTime.Now.AddBusinessDays(4);
public DateTime AddBusinessDays(DateTime dt, int nDays)
{
int weeks = nDays / 5;
nDays %= 5;
while(dt.DayOfWeek == DayOfWeek.Saturday || dt.DayOfWeek == DayOfWeek.Sunday)
dt = dt.AddDays(1);
while (nDays-- > 0)
{
dt = dt.AddDays(1);
if (dt.DayOfWeek == DayOfWeek.Saturday)
dt = dt.AddDays(2);
}
return dt.AddDays(weeks*7);
}
Without over-complicating the algorithm, you could just create an extension method like this:
public static DateTime AddWorkingDays(this DateTime date, int daysToAdd)
{
while (daysToAdd > 0)
{
date = date.AddDays(1);
if (date.DayOfWeek != DayOfWeek.Saturday && date.DayOfWeek != DayOfWeek.Sunday)
{
daysToAdd -= 1;
}
}
return date;
}
I would use this extension, remember since it is an extension method to put it in a static class.
Usage:
var dateTime = DateTime.Now.AddBusinessDays(5);
Code:
namespace ExtensionMethods
{
public static class MyExtensionMethods
{
public static DateTime AddBusinessDays(this DateTime current, int days)
{
var sign = Math.Sign(days);
var unsignedDays = Math.Abs(days);
for (var i = 0; i < unsignedDays; i++)
{
do
{
current = current.AddDays(sign);
} while (current.DayOfWeek == DayOfWeek.Saturday ||
current.DayOfWeek == DayOfWeek.Sunday);
}
return current;
}
}
}
Source:
https://github.com/FluentDateTime/FluentDateTime/blob/master/src/FluentDateTime/DateTime/DateTimeExtensions.cs
int daysToAdd = weekDaysToAdd + ((weekDaysToAdd / 5) * 2) + (((origDate.DOW + (weekDaysToAdd % 5)) >= 5) ? 2 : 0);
To wit; the number of "real" days to add is the number of weekdays you're specifying, plus the number of complete weeks that are in that total (hence the weekDaysToAdd / 5) times two (two days in the weekend); plus a potential offset of two days if the original day of the week plus the number of weekdays to add "within" the week (hence the weekDaysToAdd mod 5) is greater than or equal to 5 (i.e. is a weekend day).
Note: this works assuming that 0 = Monday, 2 = Tuesday, ... 6 = Sunday. Also; this does not work on negative weekday intervals.
I created an extension that allows you to add or subtract business days.
Use a negative number of businessDays to subtract. It seems to work in all cases.
namespace Extensions.DateTime
{
public static class BusinessDays
{
public static System.DateTime AddBusinessDays(this System.DateTime source, int businessDays)
{
var dayOfWeek = businessDays < 0
? ((int)source.DayOfWeek - 12) % 7
: ((int)source.DayOfWeek + 6) % 7;
switch (dayOfWeek)
{
case 6:
businessDays--;
break;
case -6:
businessDays++;
break;
}
return source.AddDays(businessDays + ((businessDays + dayOfWeek) / 5) * 2);
}
}
}
Example:
using System;
using System.Windows.Forms;
using Extensions.DateTime;
namespace AddBusinessDaysTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
label1.Text = DateTime.Now.AddBusinessDays(5).ToString();
label2.Text = DateTime.Now.AddBusinessDays(-36).ToString();
}
}
}
F# flavor of http://stackoverflow.com/questions/1044688 's answer:
namespace FSharpBasics
module BusinessDays =
open System;
let private weekLength = 5
(*operation*)
let addBusinessDays (numberOfBusinessDays: int) (startDate: DateTime) =
let startWeekDay = startDate.DayOfWeek
let sign = Math.Sign(numberOfBusinessDays)
let weekendSlide, businessDaysSlide =
match startWeekDay with
| DayOfWeek.Saturday when sign > 0 -> (2, -1)
| DayOfWeek.Saturday when sign < 0 -> (-1, 1)
| DayOfWeek.Sunday when sign > 0 -> (1, -1)
| DayOfWeek.Sunday when sign < 0 -> (-2, 1)
| _ -> (0, 0)
let baseStartDate = startDate.AddDays (float weekendSlide)
let days = Math.Abs (numberOfBusinessDays + businessDaysSlide) % weekLength
let weeks = Math.Abs (numberOfBusinessDays + businessDaysSlide) / weekLength
let baseWeekDay = int baseStartDate.DayOfWeek
let oneMoreWeekend =
if sign = 1 && days + baseWeekDay > 5 || sign = -1 && days >= baseWeekDay then 2
else 0
let totalDays = (weeks * 7) + days + oneMoreWeekend
baseStartDate.AddDays (float totalDays)
[<EntryPoint>]
let main argv =
let now = DateTime.Now
printfn "Now is %A" now
printfn "13 business days from now would be %A" (addBusinessDays 13 now)
System.Console.ReadLine() |> ignore
0
This is better if anyone is looking for a TSQL solution. One line of code and works with negatives.
CREATE FUNCTION[dbo].[AddBusinessDays](#Date date,#n INT)RETURNS DATE AS BEGIN
DECLARE #d INT;SET #d=4-SIGN(#n)*(4-DATEPART(DW,#Date));
RETURN DATEADD(D,#n+((ABS(#n)+#d-2)/5)*2*SIGN(#n)-#d/7,#Date)END
Here is how I did it.
I had to calculate SLA (Service Level Agreement) due dates based on a start date and number of days, and account for weekends and public holidays:
public DateTime? CalculateSLADueDate(DateTime slaStartDateUTC, double slaDays)
{
if (slaDays < 0)
{
return null;
}
var dayCount = slaDays;
var dueDate = slaStartDateUTC;
var blPublicHoliday = new PublicHoliday();
IList<BusObj.PublicHoliday> publicHolidays = blPublicHoliday.SelectAll();
do
{
dueDate = dueDate.AddDays(1);
if ((dueDate.DayOfWeek != DayOfWeek.Saturday)
&& (dueDate.DayOfWeek != DayOfWeek.Sunday)
&& !publicHolidays.Any(x => x.HolidayDate == dueDate.Date))
{
dayCount--;
}
}
while (dayCount > 0);
return dueDate;
}
blPublicHoliday.SelectAll() is a cached in-memory list of public holidays.
(note: this is a cut down version for sharing publicly, there is a reason its not an extension method)
enter code public static DateTime AddWorkDays(DateTime dt,int daysToAdd)
{
int temp = daysToAdd;
DateTime endDateOri = dt.AddDays(daysToAdd);
while (temp !=0)
{
if ((dt.AddDays(temp).DayOfWeek == DayOfWeek.Saturday)|| (dt.AddDays(temp).DayOfWeek == DayOfWeek.Sunday))
{
daysToAdd++;
temp--;
}
else
{
temp--;
}
}
while (endDateOri.AddDays(temp) != dt.AddDays(daysToAdd))
{
if ((dt.AddDays(temp).DayOfWeek == DayOfWeek.Saturday) || (dt.AddDays(temp).DayOfWeek == DayOfWeek.Sunday))
{
daysToAdd++;
}
temp++;
}
// final enddate check
if (dt.AddDays(daysToAdd).DayOfWeek == DayOfWeek.Saturday)
{
daysToAdd = daysToAdd + 2;
}
else if (dt.AddDays(daysToAdd).DayOfWeek == DayOfWeek.Sunday)
{
daysToAdd++;
}
return dt.AddDays(daysToAdd);
}
DateTime oDate2 = DateTime.Now;
int days = 8;
for(int i = 1; i <= days; i++)
{
if (oDate.DayOfWeek == DayOfWeek.Saturday)
{
oDate = oDate.AddDays(2);
}
if (oDate.DayOfWeek == DayOfWeek.Sunday)
{
oDate = oDate.AddDays(1);
}
oDate = oDate.AddDays(1);
}
Given the number of the original day in the year D and original day in the week W and the number of workdays to add N, the next weekday number is
W + N % 5.
The next day in the year (with no wraparound check) is
D + ((N / 5) * 7) + N % 5).
This is assuming that you have integer division.
Formula will be: Workday(date,no.of days,(weekday(1)))
Try this. This will help.