Determining if a day is 0 or 1

idontkno

New Member
Messages
49
Reaction score
0
Points
0
Say I wanted to set a day as 0 or 1 for weekdays only, alternating every day with an occasional day where you skip alternating and go on to the old value.

E.g. 0,1,0,1,0,break,0,1,0,1,0
 

miguelkp

Member
Messages
304
Reaction score
7
Points
18
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
 

idontkno

New Member
Messages
49
Reaction score
0
Points
0
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

Yeah, that is what I mean, but it doesn't work when you skip a day.

For instance:

Feb 1st = day 0
Feb 2nd = day 1
Feb 3rd = day 0
Feb 4th = day 1
Feb 5th = skip
Feb 8th = day 1
 

miguelkp

Member
Messages
304
Reaction score
7
Points
18
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?
 

idontkno

New Member
Messages
49
Reaction score
0
Points
0
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?

I haven't decided. I was going to put it into an ini file though.
 

miguelkp

Member
Messages
304
Reaction score
7
Points
18
So I supose that you can store only the number of skipped days and add that number to the int daycode (the function argument). Could this work for your purposes?
 
Last edited:

idontkno

New Member
Messages
49
Reaction score
0
Points
0
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?

Nope. I just looked through your code again and I realized that you thought I mean every monday = 1 or tuesday = 0.

If I added on to my February example, you would come up with this:

Feb 1st = 0
Feb 2nd = 1
Feb 3rd = 0
Feb 4th = 1
Feb 5th = skip
Feb 6th = weekend
Feb 7th = weekend
Feb 8th = 0
[...]
Feb 12th = 0
[...]
Feb 15th = 1
Feb 16th = 0
Feb 17th = 1

For the weekends, we could do this

Code:
if (date("w") > 0 && < 6)
{
//blah blah blah
}

But I have no clue how I would make the 0s and 1s work.
 

miguelkp

Member
Messages
304
Reaction score
7
Points
18
Well. I think you misunderstood me. The int daycode should be the day of the week, not the day of the month. And all should work I think :)
Every monday will be number 0. Every tuesday will be number 1. And so on. And of course, you can skip weekends, either outside the function or inside it, with a small change.

Depending on what languaje are you working, maybe you can found in Google some algorithm that calculates day of the week.
As I supose you're making some kind of PHP calendar, here you got in PHP:

http://php.net/manual/en/function.date.php

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)
 

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
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?
 
Last edited:

idontkno

New Member
Messages
49
Reaction score
0
Points
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?

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.

I would like for it to start on an arbitrary date, continue on while alternating between 0s and 1s, skipping weekends and holidays. In some cases like my apparent contradiction, counting the day as a 0 or 1 while continuing on.

I was looking for a function where I can generate a function which by inputting an arbitrary date, will tell me if it's a 0 or a 1.

In another hopefully less confusing example:
Feb 1 = 0
Feb 2 = 1
Feb 3 = 0
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
Feb 13 = weekend
Feb 14 = weekend
Feb 15 = 1
Feb 16 = 0
Feb 17 = 1

I was thinking of setting a variable in a DB and just xoring it every day, but skipping it on weekends and predefined dates.
 

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
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.
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?


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
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.
 
Last edited:

idontkno

New Member
Messages
49
Reaction score
0
Points
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.

Now we're getting some where.

However, you are wrong. That is my overall goal here. Its not a step towards my goal. It IS my goal.
 

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
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?
Is the bold text your answer?

What's your answer to:
Do you have a particular language in mind [...]?

However, you are wrong. That is my overall goal here. Its not a step towards my goal. It IS my goal.
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?
 
Last edited:

idontkno

New Member
Messages
49
Reaction score
0
Points
0
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.

The bolded text is indeed my answer.

Because my script was designed with two schedules alternating every day.
 

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
Because my script was designed with two schedules alternating every day.
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):
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
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.

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.
 
Last edited:

idontkno

New Member
Messages
49
Reaction score
0
Points
0
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):
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
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.

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.

I primarily use PHP so I have no problem parsing and reading the file.

Code:
$ini_array = parse_ini_file(myini.ini, true);
for($i=1; $i <= 28; $i++){
echo $ini_array['feb']['$i'];
}

However, after reading your python script, I'm still a little confused as to how it works.
 

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
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?

I primarily use PHP so I have no problem parsing and reading the file.
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.

However, after reading your python script, I'm still a little confused as to how it works.
These are the essential aspects:
  1. Store days to skip and ignore in a table:
    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`)
    };
    With suitable alterations to the rest of the code, column `date` could instead have type DATE.
  2. 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
  3. Calculate the number of days from an arbitrary date. You can use either the total number of days:
    Code:
    when // (60*60*24)
    or you can count just the business days. Since you're interested in the parity, it doesn't matter which.
  4. Subtract the count of ignored days (2) from the total number of days (3).
  5. Calculate the remainder of (3) modulo 2. This is the parity.
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.

In PHP, it would look like:
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
}
Only I don't recommend using a global $db variable in production code.

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.
 
Last edited:

idontkno

New Member
Messages
49
Reaction score
0
Points
0
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:
  1. Store days to skip and ignore in a table:
    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`)
    };
    With suitable alterations to the rest of the code, column `date` could instead have type DATE.
  2. 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
  3. Calculate the number of days from an arbitrary date. You can use either the total number of days:
    Code:
    when // (60*60*24)
    or you can count just the business days. Since you're interested in the parity, it doesn't matter which.
  4. Subtract the count of ignored days (2) from the total number of days (3).
  5. Calculate the remainder of (3) modulo 2. This is the parity.
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.

In PHP, it would look like:
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
}
Only I don't recommend using a global $db variable in production code.

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 that's the case, then its still not exactly what I'm looking for.

What I'm looking for is this:
I have 2 schedules that are run alternately on multiple servers
Schedule A runs on day 0
Schedule B runs on day 1
If there is a maintenance on one server, I want it to continue on. 0,1,skip,1
However, if there is an update, then I want it to skip the day and continue on the next possible day. 0,1,skip,0
 

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
If that's the case, then its still not exactly what I'm looking for.
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:
PHP:
<?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>

Produces this:
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

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.
There's the overall goal. Simply storing the next schedule to run is the more direct solution. The scheduler, in pseudocode:
Code:
if not ignore today:
    if not skip today:
        run scheduled
    set scheduled to other schedule
This assumes you run the scheduler script exactly once per day.
 
Last edited:
Top