How to find nearest future date from now with specific weekday? - algorithm

I have an appointment management scenario in which I have a field List of availableWeekDays of a person on which weekdays they are available for booking. For example if they are available on monday I have a value in availableWeekDays list as 1.
I have currentDate stored in a DateTime variable using DateTime.now().
What I have to do is first look if today's week day matches the availableWeekDay of person. If yes then bookingDate is valid else I have to look for nearest future date with weekday of person. I have tried following solution but it works for one week day as I'm using first index.
void main() {
DateTime bookingDate = DateTime.now();
int availableWeekDays = [1,4,7];
getDate(){
if(bookingDate.weekday == availableWeekDays[0]){
print("Available on $bookingDate ");
} else {
bookingDate = bookingDate.add(Duration(days: 1));
getDate();
}
}
getDate();
}
I want to find the nearest future date among all weekdays present in list.

DateTime findNearestWeekday(List<int> availableWeekdays) {
assert(availableWeekdays.isNotEmpty);
var date = DateTime.now();
final weekday = date.weekday;
for (var num in availableWeekdays) {
if (num == date.weekday) {
return date;
} else if (date.weekday < num) {
return date.add(Duration(days: num - weekday));
}
}
/// I have assumed that you will always have a sorted list of available
/// weekdays, in case you do not have a sorted list, either you can sort
/// the list first or just use this line (instead of the last one),
///
/// ```dart
/// import 'dart:math'; /// Add on Top of file.
///
/// return date.add(Duration(days: 7 - weekday + availableWeekdays.reduce(min)))
/// ```
///
/// I will prefer to pre sort the array before storing it somewhere,
/// because it will add an additional dependency dart:math
return date.add(Duration(days: 7 - weekday + availableWeekdays[0]));
}

A more efficient solution would be:
DateTime getDate() {
var currentDay = bookingDate.weekday;
var offset = (availableWeekDay - currentDay).remainder(7);
return offset == 0 ? bookingDate : bookingDate.add(Duration(days: offset));
}
Do be aware that adding "days" (multiples of 24 hours) to a date may run into daylight savings issues if the time of the bookingDate is close to midnight.

I forgot to reassign the result to the variable. This works now.
void main() {
DateTime bookingDate = DateTime.now();
int availableWeekDay = 1;
getDate(){
if(bookingDate.weekday == availableWeekDay){
print("Available on $bookingDate ");
} else {
bookingDate = bookingDate.add(Duration(days: 1));
getDate();
}
}
getDate();
}

Related

Expert Advisor timefilter doesn't work (mql5)?

I can't figure out why my timefilter doesn't work. Let's say I would like to only enter to positions between 7:35-11:30 and 14:30-22:30 and I don't want to enter a position on Friday.
The time filter only works when I create a simple EA with only a trade.Buy function and no other conditions.
The more complex EA should only enter a position when the vaule of the Supertrend indicator becomes higher/lower than the price and only in the given time intervals.
It should close the position at the next sell/buy signal (if it was a buy position then the position should be closed at the next 'sell' signal' ). When closing positions the time interval shouldn't matter it should only mater when entering a new position.
The 'TradingIsAllowed' variable should be 'true' when the current time is in the allowed time intervals but it always returns false for some reason and I can't figure out why.
It works perfectly fine when I don't use the supertrend and close trades with a simple tp/sl.
Could you please help me?
#include <Trade\Trade.mqh>
CTrade trade;
ulong posTicket;
input double Lots=0.1;
int stHandle;
int totalBars;
input ENUM_TIMEFRAMES Timeframe = PERIOD_CURRENT;
input int Periods =12;
input double Multiplier = 3.0;
//for the timefilter
input string StartTradingTime="07:35";
input string StopTradingTime="11:30";
input string StartTradingTime2="14:35";
input string StopTradingTime2="22:30";
string CurrentTime;
bool TradingIsAllowed=false;
bool TradingIsAllowed2=false;
int OnInit(){
totalBars=iBars(_Symbol,Timeframe);
stHandle = iCustom(_Symbol, Timeframe, "Supertrend.ex5", Periods, Multiplier);
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason){
}
void OnTick(){
//for the timefilter
datetime LocalTime=TimeLocal();
string HoursAndMinutes=TimeToString(LocalTime,TIME_MINUTES);
string YearAndDate=TimeToString(LocalTime, TIME_DATE);
MqlDateTime DateTimeStructure;
TimeToStruct(LocalTime, DateTimeStructure);
int DayOfWeek=DateTimeStructure.day_of_week;
datetime time = TimeLocal();
CurrentTime=TimeToString(time,TIME_MINUTES);
//this should only run if there is a new bar
int bars=iBars(_Symbol, Timeframe);
if(totalBars !=bars){
totalBars=bars;
double st[];
CopyBuffer(stHandle,0,0,3,st);
double close1 = iClose(_Symbol, Timeframe, 1);
double close2 = iClose(_Symbol, Timeframe, 2);
//BUY CONDITION
if(close1 > st[1] && close2 < st[0]){
if(posTicket > 0 ){
if(PositionSelectByTicket(posTicket)){
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL){
if (trade.PositionClose(posTicket)){
Print(__FUNCTION__," > Pos ", posTicket, "was closed..");
}
}
}
}
if(CheckTradingTime()==true || CheckTradingTime2()==true){
if(PositionsTotal()==0 && DayOfWeek!=5){
Print(__FUNCTION__, " > BOUGHT");
if(trade.Buy(Lots, _Symbol)){
if(trade.ResultRetcode() == TRADE_RETCODE_DONE){
posTicket= trade.ResultOrder();
}
}
}
}
}
else if(close1 < st[1] && close2 > st[0]){
if(posTicket > 0 ){
if(PositionSelectByTicket(posTicket)){
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY){
if (trade.PositionClose(posTicket)) {
Print(__FUNCTION__," > Pos ", posTicket, "was closed..");
}
}
}
}
if(CheckTradingTime()==true || CheckTradingTime2()==true){
if(PositionsTotal()==0 && DayOfWeek!=5){
Print(__FUNCTION__, " > SOLD");
if(trade.Sell(Lots, _Symbol)){
if(trade.ResultRetcode() == TRADE_RETCODE_DONE){
posTicket= trade.ResultOrder();
}
}
}
}
}
}
Comment (
"TradingIsAllowed", TradingIsAllowed, TradingIsAllowed2, "\n", //TradingIsAllowed always returns false..
"Current Time=", CurrentTime,"\n",
"Trading Session1=", StartTradingTime,"-" ,StopTradingTime, "\n",
"Trading Session2=", StartTradingTime2, "-", StopTradingTime2,"\n",
"Day of Week", DayOfWeek
);
}
//trading session 1
bool CheckTradingTime()
{
if(StringSubstr(CurrentTime,0,5)==StartTradingTime)
TradingIsAllowed=true;
if(StringSubstr(CurrentTime,0,5)==StopTradingTime)
TradingIsAllowed=false;
return TradingIsAllowed;
}
//trading session 2
bool CheckTradingTime2()
{
if(StringSubstr(CurrentTime,0,5)==StartTradingTime2)
TradingIsAllowed2=true;
if(StringSubstr(CurrentTime,0,5)==StopTradingTime2)
TradingIsAllowed2=false;
return TradingIsAllowed2;
}
you dont neet to write "(StringSubstr(CurrentTime,0,5)==StartTradingTime)"
you can write only "CurrentTime == StartTradingTime"

How to sort a list of timings like this [ 2:00 AM , 10:00 AM , 6:00 PM ] in dart-flutter?

I'm working on a flutter app, one of its features is to add your drug dose timings to get a reminder to take your drug. and I need to sort the timings to get the 'next_dose' to appear here :
https://drive.google.com/file/d/1j5KrRbDj0J28_FrMKy7dazk4m9dw202d/view?usp=sharing
this is an example of the list which I want to sort
[8:30 AM, 3:30 PM, 9:30 AM, 7:00 AM]
function I made to get the greater between 2 timings
int greater(String element,String element2){
var hour = element.toString().split(':')[0];
var hour2 = element2.toString().split(':')[0];
var minute = element.toString().split(':')[1].split(' ')[0];
var minute2 = element2.toString().split(':')[1].split(' ')[0];
var day = element.toString().split(':')[1].split(' ')[1];
var day2 = element2.toString().split(':')[1].split(' ')[1];
if(day == 'AM' && day2 == 'PM')
return -1;
else if(day2 == 'AM' && day == 'PM')
return 1;
else if(day == day2)
{
if(int.parse(hour) > int.parse(hour2)) return -1;
else if(int.parse(hour) < int.parse(hour2)) return 1;
else{
if(int.parse(minute) > int.parse(minute2))
return 1;
else
return -1;
}
}
here I tried to use the function to sort the list'Dose'
dose.sort((a,b)=>greater(a,b));
Instead of creating a sort callback with a lot of complicated logic, it'd be simpler if the callback parsed the time strings either into an int or into a DateTime object and compared those. For example:
/// Parses a time of the form 'hh:mm AM' or 'hh:mm PM' to a 24-hour
/// time represented as an int.
///
/// For example, parses '3:30 PM' as 1530.
int parseTime(String time) {
var components = time.split(RegExp('[: ]'));
if (components.length != 3) {
throw FormatException('Time not in the expected format: $time');
}
var hours = int.parse(components[0]);
var minutes = int.parse(components[1]);
var period = components[2].toUpperCase();
if (hours < 1 || hours > 12 || minutes < 0 || minutes > 59) {
throw FormatException('Time not in the expected format: $time');
}
if (hours == 12) {
hours = 0;
}
if (period == 'PM') {
hours += 12;
}
return hours * 100 + minutes;
}
void main() {
var list = ['8:30 AM', '3:30 PM', '9:30 AM', '7:00 AM'];
list.sort((a, b) => parseTime(a).compareTo(parseTime(b)));
print(list); // Prints: [7:00 AM, 8:30 AM, 9:30 AM, 3:30 PM]
}
Alternatively, you can use package:intl and DateFormat.parse to easily parse strings into DateTime objects.
Here we get the time slot by passing the start and end time duration.
List<String> createTimeSlot(
Duration startTime, Duration endTime, BuildContext context,
{Duration step = const Duration(minutes: 30)} // Gap between interval
) {
var timeSlot = <String>[];
var hourStartTime = startTime.inHours;
var minuteStartTime = startTime.inMinutes.remainder(60);
var hourEndTime = endTime.inHours;
var minuteEndTime = endTime.inMinutes.remainder(60);
do {
timeSlot.add(TimeOfDay(hour: hourStartTime, minute: minuteStartTime)
.format(context));
minuteStartTime += step.inMinutes;
while (minuteStartTime >= 60) {
minuteStartTime -= 60;
hourStartTime++;
}
} while (hourStartTime < hourEndTime ||
(hourStartTime == hourEndTime && minuteStartTime <= minuteEndTime));
debugPrint("Number of slot $timeSlot");
return timeSlot;
}
Function call
createTimeSlot(Duration(hours: 1, minutes: 30),
Duration(hours: 3, minutes: 30), context);
Output:
Number of slot [1:30 AM, 2:00 AM, 2:30 AM, 3:00 AM, 3:30 AM]

How to add number of days to a custom Date captured from Correlation function?

I am looking for logic which can add couple of days to a custom date(not current date)
Below is Correlation function:
web_reg_save_param("Recommended_Date",
"LB=\"start\":\"",
"RB/DIG=T##:##:##\",",
"Ord=1",
"Search=Body",
LAST);
I want to add +21 days to Recommended_Date parameter. I tried doing below thing but no luck
lr_save_datetime("%Y-%M-%D", lr_eval_string("{Recommended_Date}") + (ONE_DAY*21), "New_Date");
Can anyone please assist me.
One of our engineers prepared this example for you:
int diff_days(char * dateString, char * dateFormat) {
int year, month, day;
struct tm info;
double delta;
double days=0;
time_t today;
time(&today);
sscanf(dateString, dateFormat, &year, &month, &day);
info.tm_year = year - 1900;
info.tm_mon = month - 1;
info.tm_mday = day;
// info.tm_hour = 0;
// info.tm_min = 0;
// info.tm_sec = 0;
info.tm_isdst = -1;
mktime(&info);
delta = difftime(mktime(&info),today);
if (delta >= 0) {
days = difftime(mktime(&info),today)/ 86400.0 +1;
} else {
days = difftime(mktime(&info),today)/ 86400.0;
}
return (int)days;
}
Action()
{
int plus;
lr_save_string("2020-09-01","D2");
plus = diff_days(lr_eval_string("{D2}"),"%d-%d-%d");
lr_save_datetime("%Y-%m-%d", DATE_NOW + ONE_DAY*(21+plus), "New_Date");
lr_save_string("2020/04/05","D2");
plus = diff_days(lr_eval_string("{D2}"),"%d/%d/%d");
lr_save_datetime("%Y/%m/%d", DATE_NOW + ONE_DAY*(21+plus), "New_Date");
return 0;
}

Calculating Total Job Experience

I need to calculate the total job experience as year value. Users add experiences with starting and ending dates to their resumes, just like Linkedin. But there is no any certain pattern. For instance;
A user may have a resume like that;
Experience 2
08.2012 - 01.2015
Experience 1
01.2011 - 01.2013
The user started their second experience while the first hasn't finished yet. So resumes may have many overlapping experiences. Overlapping also may occur between more than 2. So I need to consider many cases.
I tried to visualise the experience and year relationship for you.
I just need to develop an algorithm covering all the cases for this issue.
Sort by start date
start at the beginning and accumulate overlapping experiences (i.e. treat as one)
e.g. (Jan 2012, Jan 2015), (Jan 2014, Dec 2016) overlap, so we treat it as a single experience
This "super experience" begins at the start of the first, and ends at the end of the last; (Jan 2012, Dec 2016)
This is assuming that there can be gaps in experience, so we don't want to treat the entire history as one long "super experience"
I just did this
Sort the experiences by Begin Date.
Use 2 variables, that represent the begin of work and the end called Begin
and End.
If end and begin are empty it means that is the first date, we filled with the first experience, and we calculate the month count between the begin and end of this experience and and then this months count add to our months accumulator.
if the end and begin date of next experience is not between our begin and end variables, we calculate the months count from the experience and then add it to our accumulator.
If the begin date of next experience is between our begin and end variables, we calculate the months count between our end date as begin and the experience end date as end, and then that difference add to our months accumulator.
as you can see every time we set our new end if the experience end is greater than ours.
at the end we get the months, if you divide by 12 you get the years exactly you can round it if you want
NOTE: I Mapped the experiences, if not have End it means that is equivalent to NOW
you can see all the code below
function monthDiff(d1, d2) {
var m = (d1.getFullYear() - d2.getFullYear()) * 12 +
(d1.getMonth() - d2.getMonth());
if (d1.getDate() < d2.getDate()) --m;
return m;
}
function dateCheck(from, to, check) {
var fDate, lDate, cDate;
fDate = Date.parse(from);
lDate = Date.parse(to);
cDate = Date.parse(check);
if (cDate <= lDate && cDate >= fDate) {
return true;
}
return false;
}
function calculateYearsOfExperience(experiences) {
if (!experiences) return 0;
let months = 0;
let now = new Date();
let sorted = experiences
.sort((a, b) => {
return new Date(a.begin) - new Date(b.begin);
})
.map(experience => {
if (!experience.end) experience.end = now;
return { begin: experience.begin, end: experience.end };
});
let begin;
let end;
for (var i in sorted) {
let dif = 0;
if (!end && !begin) {
dif = monthDiff(sorted[i].begin, sorted[i].end);
begin = sorted[i].begin;
end = sorted[i].end;
} else if (
!dateCheck(begin, end, sorted[i].begin) &&
!dateCheck(begin, end, sorted[i].end)
) {
dif = monthDiff(sorted[i].begin, sorted[i].end);
end = sorted[i].end;
} else if (dateCheck(begin, end, sorted[i].begin)) {
dif = monthDiff(end, sorted[i].end);
end = sorted[i].end;
}
months += dif;
}
return months / 12;
}
experiences = [
# (start date, end date),
(date(2012, 8, 1), date(2015, 1, 30)),
(date(2011, 1, 1), date(2013, 1, 30))
]
print(sum((end_date - start_date).days/365 for start_date, end_date in experiences))
Create an array full of 0. Element range: Start would be the very first hire date, last would be current date / last working date. For every year you have 12 elements that can be 0/1. After filling in the array count the elements that have the value 1. If you need to take into account the overlapping then ignore the 0/1 part and give +1 for every month worked.
This is c# code, but you'll get the steps in algorithm. It returns total number of months which you can convert into year and month format.
var sortedList = expList
.OrderBy(a => a.start_year)
.ThenBy(a => a.start_month)
.ThenBy(a => a.end_year)
.ThenBy(a => a.end_month)
.ToList();
int totalMonths = 0;
int totalDays = 0;
DateTime? prevEndDate = null;
foreach (var exp in sortedList)
{
if(exp.start_month != null && exp.start_year != null)
{
var startDate = new DateTime((int)exp.start_year, (int)exp.start_month, 1);
var endDate = (bool)exp.is_present ?
DateTime.Now :
new DateTime((int)exp.end_year, (int)exp.end_month, 1);
if (prevEndDate != null && prevEndDate > startDate)
{
startDate = (DateTime)prevEndDate;
}
var timespan = endDate.Subtract(startDate);
var tempdate = DateTime.MinValue + timespan;
totalMonths = totalMonths + (tempdate.Year - 1) * 12 + tempdate.Month - 1;
totalDays = totalDays + tempdate.Day - 1;
prevEndDate = endDate;
}
}
if (totalDays > 0)
{
totalMonths = totalMonths + 1;
}
public static function YearCalculation($id=null) {
if($id=="")
$employee_id=#Auth::guard('web_employee')->user()->id;
else
$employee_id=$id;
$employee_exp = Experience::where('employee_id',$employee_id)->orderBy("experience_from","ASC")->get();
//print_r($employee_exp ); exit;
$years = 0;
$months = 0;
$days = 0;
$sum=0;
$lastfromdate=0;
$last_endDate=0;
if(#$employee_exp!=null){
foreach(#$employee_exp as $experience){
$fdate = #$experience->experience_from;
if($experience->is_current==0){
$tdate = #$experience->experience_to;
}else{
$tdate = date("Y-m-d");
}
if($last_endDate != date("Y-m-d") ){
if( $fdate < $last_endDate ){
$start_date1 = strtotime($last_endDate);
$end_date1 = strtotime($tdate);
$interval1 = ($end_date1 - $start_date1)/60/60/24;
$sum +=$interval1;
}
else{
$start_date2 = strtotime($fdate);
$end_date2 = strtotime($tdate);
$interval2 = ($end_date2 - $start_date2)/60/60/24;
$sum +=$interval2;
}
if($last_endDate < $tdate){
$last_endDate=$tdate;
}
}
}
$years = ($sum / 365) ;
$years = floor($years);
$month = ($sum % 365) / 30.4166;
$month = floor($month);
$days = ($sum % 365) % 30.4166;
//$total=date_diff(0,$tmstamp);
//$total_year=$years.' years, ' .$month.' months and '.$days.($days==1?' day':' days');
$total_year=($years==0?'':($years==1?$years.' year':$years.' years and ')) .($month==0?'':($month==1?$month.($days>1?'+':'').' month':$month.($days>1?'+':'').' months'));
return $total_year;
}
}

How to pass Datetime externally into SQL

How to write code for getting that record By passing Date,MM,Year,HH,MM,SS
all these parameters are coming from DropdownList
public JsonResult Dif(int Day = 0, int Month=0, int Year=0, int HH, int MM, int Ss)
{
var x = (from n in db.Employees
where n.DataofBirth = (Day,Month,Year)
select n).First();
return new JsonResult { JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
You need to create an instance of DateTime:
var date = new DateTime(Year, Month, Day, HH, MM, Ss);
var x = (from n in db.Employees
where n.DataofBirth = date
select n).First();
Also, it doesn't really make sense for the parameters to have a default value... especially if it's not a valid value! Neither the year, month or day can be 0.

Resources