3

I'm trying to store chosen weekdays in one field in DB. Bitwise seem to be perfect for that, but PHP dosen't give the expected result, and i don't know why.

mon tue wnd thu fri sat sun
1   1   1   1   1   1   1
1   2   4   8   16  32  64

so to select Tue and Fri: 18 (0100100)

and for example, to check if sunday is selected: decbin(18) & decbin(64) (should return "empty"), but the reuslts are unexpected.

sql_noobe
  • 55
  • 5

2 Answers2

2

That's because you need to left-pad those binary strings with leading zeroes to the same length. decbin() creates a string that discards any leading zeroes. You're anding strings like:

10010      // 18
1000000    // 64

Either use str_pad() too add leading zeroes to a fixed length, or save a function call and use sprintf to do both the base conversion and the padding in a single step

sprintf('%08b', 18) & sprintf('%08b', 64)
Mark Baker
  • 209,507
  • 32
  • 346
  • 385
2

You don't have to work with binary strings at all to work with bit flags. Declare your days as integers 1,2,4,8 etc.

To make a value that is Monday and Friday just binary OR the values. To check that a number contains a day, binary AND them and check that the result is equal to the day your checking.

Although technically these are all binary operations, you don't actually have to ever see or use the binary strings.

Some examples with the dump results below... please ignore my use of extract, it was just quicker this way

<?php
// Day names
$dayNames = array(
    'monday',
    'tuesday',
    'wednesday',
    'thursday',
    'friday',
    'saturday',
    'sunday',
);

// Bit values
$dayValues = array();
foreach($dayNames as $key => $value) {
    $dayValues[$value] = 1 << $key;
}
var_dump($dayValues);
extract($dayValues);


// Monday and Tuesday
$monANDtue = $monday | $tuesday;
var_dump($monANDtue);
var_dump(decbin($monANDtue));



// Monday and Sunday
$monANDsun = $monday | $sunday;
var_dump($monANDsun);
var_dump(decbin($monANDsun));



// Is on Monday?
$isOnMonday = ($monANDsun & $monday) == $monday;
var_dump($isOnMonday);

// Is on Tuesday?
$isOnTuesday = ($monANDsun & $tuesday) == $tuesday;
var_dump($isOnTuesday);

// Is on Tuesday?
$isOnSunday = ($monANDsun & $sunday) == $sunday;
var_dump($isOnSunday);
?>

and the output

/vhost/virtual/sandbox/public/index.php:27
array(7) {
    [monday] = int(1) 1
    [tuesday] = int(1) 2
    [wednesday] = int(1) 4
    [thursday] = int(1) 8
    [friday] = int(2) 16
    [saturday] = int(2) 32
    [sunday] = int(2) 64
}

/vhost/virtual/sandbox/public/index.php:33
int(1) 3

/vhost/virtual/sandbox/public/index.php:34
string(2) "11"

/vhost/virtual/sandbox/public/index.php:40
int(2) 65

/vhost/virtual/sandbox/public/index.php:41
string(7) "1000001"

/vhost/virtual/sandbox/public/index.php:47
bool(true)

/vhost/virtual/sandbox/public/index.php:51
bool(false)

/vhost/virtual/sandbox/public/index.php:55
bool(true)
Christian
  • 1,557
  • 11
  • 16