Let's represent an Interval I with the following data
{i, j} "the limits" with
I.left = I.includes(i)
I.right = I.includes(j)
Note also that
I.isEmpty = (i > j) | (i = j) & (I.left.not | I.right.not)
Now take two intervals A = {a1, a2} and B = {b1, b2}. We have
A - B = A & (-inf, b1} | A & {b2, +inf)
with
(-inf, b1}.left = false
(-inf, b1}.right = B.left.not
{b2, +inf).left = B.right.not
{b2, +inf).right = false.
Note that this reduces the problem to compute two intersections, which you can do with generality. However, for the sake of completeness, let's work the details here:
A & (-inf, b1} = {a1, min(a2, b1)} with
(A & (-inf, b1}).left = A.left
(A & (-inf, b1}).right =
if(a2 < b1) A.right
elseif(a2 = b1) A.right & B.left.not
else B.left.not
and
A & {b2, +inf) = {max(a1, b2), a2} with
(A & {b2, +inf)).left =
if(a1 < b2) B.right.not
elseif(a1 = b2) A.left & B.right.not
else A.left
(A & {b2, +inf)).right = A.right
Since the difference can be reduced to the union of two intersections it's worth resolving the intersection in the general case, between two intervals A = {a1, a2} and B = {b1, b2}.
A & B = {max(a1, b1), min(a2, b2)} with
(A & B).left = if(a1 < b1) B.left elseif(a1 = b1) A.left & B.left else A.left
(A & B). right = if(a2 < b2) A.right elseif(a2 = b2) A.right & B.right else B.right