def day_number(int daycode, bol original = false)
if(original == true)
return day % 2
else
return day
end
end
Do you mean monday = 0 = 0; tuesday = 1 = 1; wednesday = 2 = 0; thursday = 3 = 1; friday = 4 = 0 (day = original = newcode). Don't you?
And that you can use this 0 or 1 valor and original valor at.
Then if I understood you well, you can make a function like this (this is more a pseudo code than a true language)
Code:def day_number(int daycode, bol original = false) if(original == true) return day % 2 else return day end end
Where or how do you 'save' the skip-days info? I mean, do you use (or plan to use) a MySQL database to say the script 'hey dude, skip that day!' or something like that?
So I supose that you can store onle the number of skipped days and add that number to the int daycode (the function argument). Could this work for your purposes?
if (date("w") > 0 && < 6)
{
//blah blah blah
}
PHP:string date ( string $format [, int $timestamp ] )
Returns a string formatted according to the given format string using the given integer timestamp or the current time if no timestamp is given. In other words, timestamp is optional and defaults to the value of time().
Parameters:
[...]
w = Numeric representation of the day of the week = 0 (for Sunday) through 6 (for Saturday)
This contradicts the earlier example, where you assigned a value of 1 to Feb. 8th. Getting the count of days mod 2 will do what you want, but you still haven't specified where you want to start counting from. The beginning of the week? Month? Year? An arbitrary date?Feb 1st = 0
Feb 2nd = 1
Feb 3rd = 0
Feb 4th = 1
Feb 5th = skip
Feb 6th = weekend
Feb 7th = weekend
Feb 8th = 0
This contradicts the earlier example, where you assigned a value of 1 to Feb. 8th. Getting the count of days mod 2 will do what you want, but you still haven't specified where you want to start counting from. The beginning of the week? Month? Year? An arbitrary date?
If you told us the overall goal, it would be easier to help you.
Furthermore, do you want to generate the days as well as the values? That is, does the code need to skip weekends and skipped days, or merely return a value when given a day count?
Do you have a particular language in mind, are you looking for algorithms?
That's not an overall goal, that's a step to the goal. What use is assigning a 0 or 1 to a day? What's the purpose of the assignment?My overall goal is as I stated it before. Assigning a number to a day, in which, alternates every other day unless there is an exception, such as a weekend or holiday.
This still isn't consistent. Feb 11 is skipped but not counted, while Feb 5 is counted. Did you mean to assign a 1 to Feb 12, or do you want to skip some days without counting them and skip others while still counting them? Note that if you're counting a day, it doesn't matter whether or not it's skipped.Feb 4 = 1
Feb 5 = skipped, but counts as 0
Feb 6 = weekend
Feb 7 = weekend
Feb 8 = 1
Feb 9 = 0
Feb 10 = 1
Feb 11 = skipped
Feb 12 = 0
That's not an overall goal, that's a step to the goal. What use is assigning a 0 or 1 to a day? What's the purpose of the assignment?
This still isn't consistent. Feb 11 is skipped but not counted, while Feb 5 is counted. Did you mean to assign a 1 to Feb 12, or do you want to skip some days without counting them and skip others while still counting them? Note that if you're counting a day, it doesn't matter whether or not it's skipped.
Is the bold text your answer?Did you mean to assign a 1 to Feb 12, or do you want to skip some days without counting them and skip others while still counting them?
Do you have a particular language in mind [...]?
Really? Why do you care that Feb 1st is 0 and Feb 10th is 1? It's an entirely arbitrary valuation. Why does it matter whether or not you count some days?However, you are wrong. That is my overall goal here. Its not a step towards my goal. It IS my goal.
Is the bold text your answer?
Really? Why do you care that Feb is 0 and Feb 10 is 1? It's an entirely arbitrary valuation.
Which suggests there is an overall goal involving picking a schedule. This is important because the requirements are dependent on the overall goal. If you know why the code needs to perform a task, you can figure out the behavior of the task. Inversely, without knowing why a task should be done, it's nigh impossible to know exactly what should be done.Because my script was designed with two schedules alternating every day.
import datetime
def isWeekend(when):
"""Returns true iff 'when' is on a weekend.
Arguments:
when: a Unix timestamp
"""
return datetime.datetime.utcfromtimestamp(when).weekday() >= 5
def isDayUncounted(when):
"""Returns true iff when shouldn't be counted for scheduling purposes.
Arguments:
when: a Unix timestamp
"""
return isWeekend(when)
|| 0 < count of (SELECT `date` FROM `days` WHERE `date`=:when AND `ignore`=True)
def businessDays(when):
"""Returns the count of business days from the start of the epoch to 'when'.
Arguments:
when: a Unix timestamp
Preconditions:
'when' is not on a weekend.
"""
days = when // (60*60*24)
weeks = days // 7
dayOfWeek = days % 7
# Epoch begins on a Thursday, so Sat is day 2
if dayOfWeek > 1:
dayOfWeek -= 2
return weeks * 5 + dayOfWeek
def countPrecedingIgnored(when):
"""Returns number of days preceding 'when' that aren't counted for scheduling purposes. If 'when' is itself ignored, it's included in the count.
Arguments:
when: a Unix timestamp
"""
return SELECT COUNT(*) FROM `days` WHERE `date`<=:when AND `ignore`=True
def schedulingDays(when):
"""Returns the count of days on the schedule from the start of the epoch to 'when'.
Arguments:
when: a Unix timestamp
Preconditions:
'when' is neither on a weekend nor an ignored weekday
"""
return businessDays(when) - countPrecedingIgnored(when)
def dayParity(when):
"""Returns the schedule parity of day 'when'. The beginning of the epoch is defined to have even parity.
Arguments:
when: a Unix timestamp
Preconditions:
'when' is neither on a weekend nor an ignored weekday
"""
return schedulingDays(when) % 2
# Alternate implementation, since counting weekends won't affect parity:
#return (when // (60*60*24) - countPrecedingIgnored(when)) % 2
Which suggests there is an overall goal involving picking a schedule. This is important because the requirements are dependent on the overall goal. If you know why the code needs to perform a task, you can figure out the behavior of the task. Inversely, without knowing why a task should be done, it's nigh impossible to know exactly what should be done.
In any case, there's now enough information to suggest a solution. In Python mixed with SQL (untested):
The problem can be solved in essentially two lines (the body of countPrecedingIgnored and the alternate implementation of dayParity), but I've included more for the sake of completeness.Code:import datetime def isWeekend(when): """Returns true iff 'when' is on a weekend. Arguments: when: a Unix timestamp """ return datetime.datetime.utcfromtimestamp(when).weekday() >= 5 def isDayUncounted(when): """Returns true iff when shouldn't be counted for scheduling purposes. Arguments: when: a Unix timestamp """ return isWeekend(when) || 0 < count of (SELECT `date` FROM `days` WHERE `date`=:when AND `ignore`=True) def businessDays(when): """Returns the count of business days from the start of the epoch to 'when'. Arguments: when: a Unix timestamp Preconditions: 'when' is not on a weekend. """ days = when // (60*60*24) weeks = days // 7 dayOfWeek = days % 7 # Epoch begins on a Thursday, so Sat is day 2 if dayOfWeek > 1: dayOfWeek -= 2 return weeks * 5 + dayOfWeek def countPrecedingIgnored(when): """Returns number of days preceding 'when' that aren't counted for scheduling purposes. If 'when' is itself ignored, it's included in the count. Arguments: when: a Unix timestamp """ return SELECT COUNT(*) FROM `days` WHERE `date`<=:when AND `ignore`=True def schedulingDays(when): """Returns the count of days on the schedule from the start of the epoch to 'when'. Arguments: when: a Unix timestamp Preconditions: 'when' is neither on a weekend nor an ignored weekday """ return businessDays(when) - countPrecedingIgnored(when) def dayParity(when): """Returns the schedule parity of day 'when'. The beginning of the epoch is defined to have even parity. Arguments: when: a Unix timestamp Preconditions: 'when' is neither on a weekend nor an ignored weekday """ return schedulingDays(when) % 2 # Alternate implementation, since counting weekends won't affect parity: #return (when // (60*60*24) - countPrecedingIgnored(when)) % 2
Note that storing skipped & ignored days in a file is a bad idea because while this gives you persistence, you'll need to write code for other tasks not already supported by the host language, such as parsing the file and finding ignored days.
$ini_array = parse_ini_file(myini.ini, true);
for($i=1; $i <= 28; $i++){
echo $ini_array['feb']['$i'];
}
There's still the problem of fetching data, which is (generally speaking) the most difficult. If you use the right data structure (an array indexed by month, then day, isn't it), it's not too hard to get ignored days before a given date. This is exactly the sort of problem SQL is intended to make easy, so I recommend using a database. Read "Re: Microsoft SQL Server (a rant)" for more advantages of using a proper DB.I primarily use PHP so I have no problem parsing and reading the file.
These are the essential aspects:However, after reading your python script, I'm still a little confused as to how it works.
CREATE TABLE `days` (
`id` INT PRIMARY KEY AUTO_INCREMENT,
`date` INT NOT NULL,
`skip` BOOL NOT NULL DEFAULT True,
`ignore` BOOL NOT NULL,
...
UNIQUE (`date`)
};
SELECT COUNT(*) FROM `days` WHERE `date` <= :when AND `ignore`=True
when // (60*60*24)
function countPrecedingIgnored($when) {
global $db;
static $stmt = null;
if (is_null($stmt)) {
$stmt = $db->prepare("SELECT COUNT(*) FROM `days` WHERE `date`<=:when AND `ignore`=True");
}
$stmt->execute(array(':when' => $when));
return $stmt->fetchColumn();
}
function dayParity($when) {
return ((int)($when / (60*60*24)) - countPrecedingIgnored($when)) % 2
}
The question of what the overall goal is is still open, though it's not as important as the task behavior is now well defined. However, there still might be a better way of achieving the goal. Do you have any more information about how the values are used?
There's still the problem of fetching data, which is (generally speaking) the most difficult. If you use the right data structure (an array indexed by month, then day, isn't it), it's not too hard to get ignored days before a given date. This is exactly the sort of problem SQL is intended to make easy, so I recommend using a database. Read "Re: Microsoft SQL Server (a rant)" for more advantages of using a proper DB.
These are the essential aspects:
In this case, the beginning of the Unix epoch (Jan 1, 1970) was picked as the arbitrary date because that's what timestamp based functions use.
- Store days to skip and ignore in a table:
With suitable alterations to the rest of the code, column `date` could instead have type DATE.Code:CREATE TABLE `days` ( `id` INT PRIMARY KEY AUTO_INCREMENT, `date` INT NOT NULL, `skip` BOOL NOT NULL DEFAULT True, `ignore` BOOL NOT NULL, ... UNIQUE (`date`) };
- Count the ignored days from an arbitrary date to the date of interest, inclusive:
Code:SELECT COUNT(*) FROM `days` WHERE `date` <= :when AND `ignore`=True
- Calculate the number of days from an arbitrary date. You can use either the total number of days:
or you can count just the business days. Since you're interested in the parity, it doesn't matter which.Code:when // (60*60*24)
- Subtract the count of ignored days (2) from the total number of days (3).
- Calculate the remainder of (3) modulo 2. This is the parity.
In PHP, it would look like:
Only I don't recommend using a global $db variable in production code.PHP:function countPrecedingIgnored($when) { global $db; static $stmt = null; if (is_null($stmt)) { $stmt = $db->prepare("SELECT COUNT(*) FROM `days` WHERE `date`<=:when AND `ignore`=True"); } $stmt->execute(array(':when' => $when)); return $stmt->fetchColumn(); } function dayParity($when) { return ((int)($when / (60*60*24)) - countPrecedingIgnored($when)) % 2 }
The business days calculations is based on the fact that a week has 5 business days. Count the number of preceding weeks, multiply by 5 and add the number of business days in the current week and you have the number of business days from an arbitrary date.
If what's the case? You've quoted my whole post, so I can't tell which part you're referring to. The code produces the behavior you've described. Running this:If that's the case, then its still not exactly what I'm looking for.
<?php
// localDB.php provides LocalDB::connect
include_once('localDB.php');
function day2timestamp($day) {
return mktime(0, 0, 0,
($day / 100) % 100,
$day % 100,
(int)($day / 10000)
);
}
class QueryCache {
private $db, $queries = array();
function __construct($db) {
$this->db = $db;
}
function get($key, $statement) {
if (! isset($this->queries[$key])) {
$this->queries[$key] = $this->db->prepare($statement);
}
return $this->queries[$key];
}
}
class Scheduler {
private $qcache;
function __construct($db) {
$this->qcache = new QueryCache($db);
}
static function isWeekend($date) {
return strftime('%u', $date) >= 6;
}
function countIgnored($date) {
$query = $this->qcache->get(__FUNCTION__, 'SELECT count(`ignore`) FROM `days` WHERE `day`<=? AND `ignore`=True');
$query->execute(array($date));
return $query->fetchColumn();
}
// requires PHP >= 5.3
function skipignore($date) {
$query = $this->qcache->get(__FUNCTION__, 'SELECT `skip`, `ignore` FROM `days` WHERE `day`=?');
try {
$query->execute(array($date));
$rslt = $query->fetch(PDO::FETCH_ASSOC);
if ($rslt) {
return array_keys(array_filter($rslt, function($x) {return $x;}));
}
} catch (PDOException $exc) {}
return array();
}
/*
Arguments:
day: a date encoded as a number of the form YYYYMMDD.
*/
function which($date) {
if ($this->isWeekend($date)) {
return 'weekend';
}
if ($status = $this->skipignore($date)) {
return implode(',', $status);
} else {
return ((int)($date/(60*60*24)) - $this->countIgnored($date)) % 2 ? 'A' : 'B';
}
}
}
?>
<pre><?php
$scheduler = new Scheduler(LocalDB::connect());
$base = 20100200;
for ($i=1; $i <= 17; ++$i) {
$day = $i+$base;
$ts = day2timestamp($day);
try {
$which = $scheduler->which($ts);
} catch (PDOException $exc) {
$which = 'error: ' . $exc;
}
echo "Feb $i = $which\n";
}
?></pre>
Feb 1 = A
Feb 2 = B
Feb 3 = A
Feb 4 = B
Feb 5 = skip
Feb 6 = weekend
Feb 7 = weekend
Feb 8 = B
Feb 9 = A
Feb 10 = B
Feb 11 = skip,ignore
Feb 12 = A
Feb 13 = weekend
Feb 14 = weekend
Feb 15 = B
Feb 16 = A
Feb 17 = B
There's the overall goal. Simply storing the next schedule to run is the more direct solution. The scheduler, in pseudocode:What I'm looking for is this:
I have 2 schedules that are run alternately on multiple servers, Schedule A [and] Schedule B [...] If there is a maintenance on one server, I want it to continue on. [...] However, if there is an update, then I want it to skip the day and continue on the next possible day.
if not ignore today:
if not skip today:
run scheduled
set scheduled to other schedule