Determine if current time between multiple time spans - c#

I'm having trouble figuring out which tradings session any particular time is in.
There are four possible sessions, show in this picture taken from ForexFactory.com
I have this method that I need to check is currentTime is during the specified trading session.
public bool IsTradingSession(TradingSession tradingSession, DateTime currentTime)
{
//currentTime is in local time.
//Regular session is 5PM - next day 5PM, this is the session in the picture.
//Irregular sessions also occur for example late open (3AM - same day 5PM) or early close (5PM - next day 11AM)
DateTime sessionStart = Exchange.ToLocalTime(Exchange.CurrentSessionOpen);
DateTime sessionEnd = Exchange.ToLocalTime(Exchange.CurrentSessionClose);
if(tradingSession == TradingSession.Sydney)
return ....... ? true : false;
if(tradingSession == TradingSession.Tokyo)
return ....... ? true : false;
if(tradingSession == TradingSession.London)
return ....... ? true : false;
if (tradingSession == TradingSession.NewYork)
return ....... ? true : false;
return false;
}
Use:
bool isSydneySession = IsTradingSession(TradingSession.Sydney, CurrentTime);
bool isTokyoSession = IsTradingSession(TradingSession.Tokyo, CurrentTime);
bool isLondonSession = IsTradingSession(TradingSession.London, CurrentTime);
bool isNewYorkSession = IsTradingSession(TradingSession.NewYork, CurrentTime);
Thank you

I'd suggest writing a simple function for each trading session, which takes a DateTime and returns a bool indicating if it's open at that time.
var sydneyOpen = new TimeSpan(17, 0, 0);
var sydneyClose = new TimeSpan(2, 0, 0);
Func<DateTime, bool> isOpenInSydney = d =>
(d.TimeOfDay > sydneyOpen || d.TimeOfDay < sydneyClose);
// same for other markets, write a function to check against two times
Then place these into a Dictionary<TradingSession, Func> like this for generic retrieval...
var marketHours = new Dictionary<TradingSession, Func<DateTime, bool>>();
marketHours.Add(TradingSession.Sydney, isOpenInSydney);
// add other markets...
And then your existing method simply selects the appropriate function for the given TradingSession and applies it
public bool IsTradingSession(TradingSession tradingSession, DateTime currentTime)
{
var functionForSession = marketHours[tradingSession];
return functionForSession(currentTime);
}
I don't believe you need UTC time here as long as your application only runs in a single timezone, but daylight savings might cause problems.
A nice way to account for the problem of trading sessions which cover two days, as opposed to just one day, is to write a helper that precisely considers whether it's a 'cross-day' trading session and applies a different rule for you:
private bool IsBetween(DateTime now, TimeSpan open, TimeSpan close)
{
var nowTime = now.TimeOfDay;
return (open < close
// if open is before close, then now must be between them
? (nowTime > open && nowTime < close)
// otherwise now must be *either* after open or before close
: (nowTime > open || nowTime < close));
}
and then
var sydneyOpen = new TimeSpan(17, 0, 0);
var sydneyClose = new TimeSpan(2, 0, 0);
Func<DateTime, bool> isOpenInSydney = d => IsBetween(d, sydneyOpen, sydneyClose);

You can compare with > & < or compare ticks.
See related questions: Check if datetime instance falls in between other two datetime objects
To avoid the multiple if statements, you could also create a TradingSession object with start and end time and define a property/function to check if in session. When I have big switch or if blocks, it usually indicates a missed OO opportunity :)
TradingSession sydneySession = new TradingSession
{
StartTimeUtc = ...;
EndTimeUtc = ...;
}
The trading session object could then have a property IsInSession.
public bool IsInSession
{
get {
return DateTime.UTCNow >= StartTimeUtc && DateTime.UTCNow <= EndTimeUtc;
}
}
This uses UTC time to eliminate time zone issues.

You need to normalize your local times to UTC. You can then compare times across regions.
For each trading session, you need to know the session start and end time in UTC.
You need the current time in UTC. DateTime.UtcNow, for example.
You can then perform range comparisons for each trading session window:
if(tradingSession == TradingSession.Sydney)
return currentTimeUtc >= sydneyStartTimeUtc && currentTimeUtc <= sydneyEndTimeUtc;
etc...
If you're trying to validate that a transaction time is valid for a transaction on a particular trading session, this will work fine.
If however you're trying to figure out what trading session a trade belongs to based on its time, you will have multiple answers sometimes because the trading sessions overlap. Multiple trading sessions may be valid for a given time.

Related

Comparing timespan object if it's between hours in C#

I want to filter an array of objects. The goal is to filter the objects between two timespan objects:
TimeSpan tsFrom = TimeSpan.Parse("16:00");
TimeSpan tsTo = TimeSpan.Parse("00:59");
For example I have this object:
TimeSpan dateObject = TimeSpan.Parse("22:05:22");
The problem comes when I try to compare if the dateObject is between tsFrom and tsTo:
if (dateObject > tsFrom && dateObject < tsTo)
{
// do something ....
}
This won't work for cases like that. Do you have any ideas how I can make this work ?
You're wanting to works with times of day. The TimeSpan data type works with time spans (somewhat obvious to say). These are distinct concepts.
Times of day are precisely what motivated the creation of the new TimeOnly type in .NET 6. It has an IsBetween method:
Determines if a time falls within the range provided. Supports both "normal" ranges such as 10:00-12:00, and ranges that span midnight such as 23:00-01:00.
Note that IsBetween use the more sensible convention of inclusive start, exclusive end which means that you'd use 01:00 as the to moment and not accidentally exclude e.g. 00:59:17 from your period
For older versions, I'd suggest you realise that if To is less than From (e.g. it's representing a period that crosses midnight) you should check:
if ((tsTo > tsFrom && dateObject >= tsFrom && dateObject < tsTo) ||
(tsFrom > tsTo && (dateObject < tsTo || dateObject >= tsFrom)))
{
}
Note, again, that this logic is assuming inclusive From and exclusive To (Your original logic treated both ends as exclusive which is rarely correct)
The problem with this one is that you're trying to use the timeSpan method in the wrong way, if I got it right you are trying to check if the dateObject time comes between tsFrom and tsTo, the problem is that you are trying to refer to a different day with the tsTo, something that timespan can not handle.
I fixed it using dateTime to specify at least the day the time is taken from, i suggest changing the code to this
string datevalue = #"15/03/2021 16:00:00";
DateTime start = DateTime.Parse(datevalue);
datevalue = #"16/03/2021 00:59:00";
DateTime end = DateTime.Parse(datevalue);
datevalue = #"15/03/2021 22:05:22";
DateTime obj = DateTime.Parse(datevalue);
if (obj > start && obj < end)
{
//Do something
}

Difficulty comparing differences in DateTimes

I have a DateTime variable called "lastActivated", that is set to DateTime.Now when the Form_Activated event fires. The goal is to make sure something doesn't happen within the first 1 second of a user clicking the screen from another screen.
DateTime? lastActivate = null; //used to determine the last time the screen was focused.
private void Form1_Activated(object sender, EventArgs e)
{
lastActivate = DateTime.Now;
}
The code for determining whether it has been longer than 1 second looks like
TimeSpan oneSec = new TimeSpan(0,0,1);
if (lastActivate == null || (TimeSpan)(lastActivate - DateTime.Now) > oneSec)
{
//stuff
}
The above if statement always, ALWAYS fails. Even when the values are:
lastActivate {11/30/2013 10:23:21 AM} System.DateTime?
now {11/30/2013 10:32:48 AM} System.DateTime
(I made a temp value DateTime now = DateTime.Now so I could paste the value here, since I couldn't directly access DateTime.Now's value)
Does anyone have any suggestions on what I'm doing wrong, and what I should change to get it to accomplish the goal I am after?
Thanks!
You can test the time between two dates by doing this:
var lastActivated = DateTime.Now;
if (DateTime.Now.Subtract(lastActivated).TotalSeconds > 1)
{
// Do whatever you need.
}
DateTime.Subtract(DateTime) returns a TimeSpan of the time difference between the two given dates.
Last active date is less than current time, you should subtract it from current time:
if (!lastActivate.HasValue || (DateTime.Now - lastActivate.Value).TotalSeconds > 1)
{
//stuff
}
Problem : You are subtracting in reverse order, you should subtract the lastActivate Time from the current Time(DateTime.Now).
otherwise you will always get -ve value when you subtract DateTime.Now from lastActivate as lastActivate time is always less than the Current Time (DateTime.Now).
Solution :
This:
(TimeSpan)(lastActivate - DateTime.Now)
Should be :
(TimeSpan)(DateTime.Now - lastActivate)
Complete Code:
TimeSpan oneSec = new TimeSpan(0,0,1);
if (lastActivate == null || (TimeSpan)(DateTime.Now - lastActivate) > oneSec)
{
//stuff
}

Time check spanning 2 days

I am creating a windows service, which checks folders, other services ect. and sends alert textmessages if any of these are down. However, I am not interested in getting alert messages during a given period of time (from 23.00 evening to 07.00 morning).
The service is set up through an XML configuration file, where this period of silence can be predefined.
I need a method to check if the service is operating in the period of time, so it will suspend text messaging. The service checks for this period every 5 minutes, so I cannot figure out how to cope shifting of days, during these checks.
To elaborate:
My current code:
bool silende = false;
DateTime silenceModeFrom = new DateTime(
DateTime.Now.Year,
DateTime.Now.Month,
DateTime.Now.Day,
int.Parse(doc.XPathSelectElement(
"//SurveilanceServiceConfig/SilenceModeTimeFrom").Value),
00,
00);
DateTime silenceModeTo = silenceModeFrom.AddHours(
int.Parse(doc.XPathSelectElement(
"//SurveilanceServiceConfig/SilenceModeTimeHours").Value));
if (DateTime.Now > silenceModeFrom && DateTime.Now < silenceModeTo)
{
silence = true;
}
In this code, the check works if it is made before 24.00, but not after as DateTime.Now.Day etc., will be the next day. So in theory, code only validates silence period as being from 23.00 to 24.00 per day.
You aren't that far off...
There is a slight issue with your code as it stands, everytime you call DateTime.Now the time would have changed - you need to capture that instance of time when the service is triggered i.e.
var instant = DateTime.Now;
DateTime silenceModeFrom = new DateTime(instant.Year, instant.Month, instant.Day, int.Parse(doc.XPathSelectElement("//SurveilanceServiceConfig/SilenceModeTimeFrom").Value), 00, 00);
DateTime silenceModeTo = silenceModeFrom.AddHours(int.Parse(doc.XPathSelectElement("//SurveilanceServiceConfig/SilenceModeTimeHours").Value));
bool silence = instant.TimeOfDay >= silenceModeFrom.TimeOfDay && instant <= silenceModeTo;
Looking at this code though, your time window appears wrong. You aren't really interested in the Date at all here - it's really just the time. Therefore, anything between 23:00hrs - 07:00hrs is considered the "silent" period i.e.
int curHour = DateTime.Now.Hour;
int silenceStartHour = int.Parse(doc.XPathSelectElement("//SurveilanceServiceConfig/SilenceModeTimeFrom").Value);
int silenceEndHour = int.Parse(doc.XPathSelectElement("//SurveilanceServiceConfig/SilenceModeTimeHours").Value);
bool silence = curHour > silenceStartHour || curHour < silenceEndHour;
The logic for determining whether you are in the silent period can be improved slightly to account for a range that is all in one day, or a range that is split over midnight.
bool silence = silenceStartHour <= silenceEndHour
? (curHour >= silenceStartHour && curHour < silenceEndHour)
: (curHour >= silenceStartHour || curHour < silenceEndHour);

Time between interval for trading sessions

I'm having trouble figuring out which tradings session any particular time is in.
There are four possible sessions, show in this picture taken from ForexFactory.com
I have this method that I need to check is currentTime is during the specified trading session.
public bool IsTradingSession(TradingSession tradingSession, DateTime currentTime)
{
//Regular session is 5PM - next day 5PM, this is the session in the picture.
//Irregular sessions also occur for example late open (3AM - same day 5PM) or early close (5PM - next day 11AM)
DateTime sessionStart = Exchange.CurrentSessionOpen;
DateTime sessionEnd = Exchange.CurrentSessionClose;
if(tradingSession == TradingSession.Sydney)
return ....... ? true : false;
if(tradingSession == TradingSession.Tokyo)
return ....... ? true : false;
if(tradingSession == TradingSession.London)
return ....... ? true : false;
if (tradingSession == TradingSession.NewYork)
return ....... ? true : false;
return false;
}
Use:
bool isSydneySession = IsTradingSession(TradingSession.Sydney, CurrentTime);
bool isTokyoSession = IsTradingSession(TradingSession.Tokyo, CurrentTime);
bool isLondonSession = IsTradingSession(TradingSession.London, CurrentTime);
bool isNewYorkSession = IsTradingSession(TradingSession.NewYork, CurrentTime);
Thanks for any help
First you need the datasource of the DateTimes (start and end) for each market. Then,
based on the argument currentTime you can check if it lies within by doing a simple check like:
if (currentTime.Ticks >= marketOpen.Ticks && currentTime.Ticks <= marketClose.Ticks)
{
//Market is open!
}
The above is the assumption that currentTime is in the same timezone as the market. If it's not, then I'd suggest converting all times in question to UTC so there is no question of whether you have the right timezone.

How can I get correct payperiod from date?

I feel like this is math problem more than anything. My company has employees all over the country. Some parts of the company are on an "odd" pay cycle and some are on "even". I call the starting date of a given pay period a "payperiod". I need to do two things:
1) determine the payperiod in which a given date falls
//Something like this:
public static DateTime getPayPeriodStartDate(DateTime givenDate, string EvenOrOdd)
{ .. }
2) get a list of payperiods between two dates:
//Something like this:
public static List<DateTime> getPayPeriodsBetween(DateTime start, DateTime end, string EvenOrOdd)
{ .. }
I'm using a couple dates as fixed standards on which to base any future pay period dates. The fixed standard dates for even and odd are as follows:
Even - 01/04/09
Odd - 01/11/09
Each pay period starts on the sunday of the week and goes for two weeks. For instance, using the standard dates above, the first even pay period starts on 01/04/09 and ends on 01/17/09. The first odd pay period starts on 01/11/09 and ends on 01/24/09. As you can see, there is some overlap. We have thousands of employees so it's necessary to split them up a bit.
I have a solution that is based on week numbers but it's clunky and has to be "fixed" every new year. I'm wondering how you would handle this.
Not fully optimized or tested, but this is what I came up with:
const int DaysInPeriod = 14;
static IEnumerable<DateTime> GetPayPeriodsInRange(DateTime start, DateTime end, bool isOdd)
{
var epoch = isOdd ? new DateTime(2009, 11, 1) : new DateTime(2009, 4, 1);
var periodsTilStart = Math.Floor(((start - epoch).TotalDays) / DaysInPeriod);
var next = epoch.AddDays(periodsTilStart * DaysInPeriod);
if (next < start) next = next.AddDays(DaysInPeriod);
while (next <= end)
{
yield return next;
next = next.AddDays(DaysInPeriod);
}
yield break;
}
static DateTime GetPayPeriodStartDate(DateTime givenDate, bool isOdd)
{
var candidatePeriods = GetPayPeriodsInRange(givenDate.AddDays(-DaysInPeriod), givenDate.AddDays(DaysInPeriod), isOdd);
var period = from p in candidatePeriods where (p <= givenDate) && (givenDate < p.AddDays(DaysInPeriod)) select p;
return period.First();
}
I haven't tested for many test cases, but I think this fits the bill:
public static DateTime getPayPeriodStartDate(DateTime givenDate, string EvenOrOdd)
{
DateTime newYearsDay = new DateTime(DateTime.Today.Year, 1, 1);
DateTime firstEvenMonday = newYearsDay.AddDays((8 - (int)newYearsDay.DayOfWeek) % 7);
DateTime firstOddMonday = firstEvenMonday.AddDays(7);
TimeSpan span = givenDate - (EvenOrOdd.Equals("Even") ? firstEvenMonday : firstOddMonday);
int numberOfPayPeriodsPast = span.Days / 14;
return (EvenOrOdd.Equals("Even") ? firstEvenMonday : firstOddMonday).AddDays(14 * numberOfPayPeriodsPast);
}
public static List<DateTime> getPayPeriodsBetween(DateTime start, DateTime end, string EvenOrOdd)
{
DateTime currentPayPeriod = getPayPeriodStartDate(start, EvenOrOdd);
if (currentPayPeriod < start) currentPayPeriod = currentPayPeriod.AddDays(14);
List<DateTime> dtList = new List<DateTime>();
while (currentPayPeriod <= end)
{
dtList.Add(currentPayPeriod);
currentPayPeriod = currentPayPeriod.AddDays(14);
}
return dtList;
}
I am sure it can be improved.
I had a need to do something similar and was able to do it very easily using LINQ. Simply build up a List for even and odd and then query between dates from the odd/even as necessary. Also, I recommend you move to an emum for parameters like EvenOrOdd where you have fixed values.
I had a similar problem a few months ago, and I ended up writing a quick script to create entries in a database for each pay period so I never had to actually do the math. This way, The system works the same speed, and doesn't have to do any slow iterations every time a period is requested.
That being said, you can always take the starting date, and add two weeks (or however long your periods are) over and over until you reach the dates you specify in the function call. This is a bit ugly, and the longer it sits in production, the slower it gets (since the dates are getting further and further apart).
Both ways are trivial to implement, it's just a matter of what kind of resources you have at hand to tackle the issue.
So, for number 1: Start with either 1/4/2009 or 1/11/2009 (depending on even/odd pay week) and add 2 weeks until the givenDate is less than the date you're testing + 2 weeks. That's the start of the period.
For number 2: Same thing, start at the date and add 2 weeks until you're within the date range. While you're there, add each item to a list. As soon as you're past the last date, break out of your loop and return your shiny new list.
If you used my method and went with a database to house all this info, it turns into 2 simple queries:
1)SELECT * FROM payperiods WHERE startdate<=givenDate ORDER BY startdate LIMIT 1
2) SELECT * FROM payperiods WHERE startdate>=givenDate AND enddate<=givenDate ORDER BY startdate
It works perfectly. I have tested.
public static DateTime GetFirstDayOfWeek(DateTime dayInWeek)
{
CultureInfo _culture = (CultureInfo)CultureInfo.CurrentCulture.Clone();
CultureInfo _uiculture = (CultureInfo)CultureInfo.CurrentUICulture.Clone();
_culture.DateTimeFormat.FirstDayOfWeek = DayOfWeek.Monday;
_uiculture.DateTimeFormat.FirstDayOfWeek = DayOfWeek.Monday;
System.Threading.Thread.CurrentThread.CurrentCulture = _culture;
System.Threading.Thread.CurrentThread.CurrentUICulture = _uiculture;
// CultureInfo defaultCultureInfo = CultureInfo.CurrentCulture;
DayOfWeek firstDay = _culture.DateTimeFormat.FirstDayOfWeek;
DateTime firstDayInWeek = dayInWeek.Date;
// Logic Of getting pay period Monday(Odd monday)
int i = Convert.ToInt32(firstDay);
while (firstDayInWeek.DayOfWeek != firstDay)
if (i % 2 != 0)
{ firstDayInWeek = firstDayInWeek.AddDays(-1); }
else
{
firstDayInWeek = firstDayInWeek.AddDays(-2);
}
return firstDayInWeek;
}

Categories