desc: Test basic time arithmetic
tests:
  - def: rt1 = 1375147296.681
  - def: rt2 = 1375147296.682
  - def: rt3 = 1375147297.681
  - def: rt4 = 2375147296.681
  - def: rts = [rt1, rt2, rt3, rt4]

  - def: t1 = r.epoch_time(rt1)
  - def: t2 = r.epoch_time(rt2)
  - def: t3 = r.epoch_time(rt3)
  - def: t4 = r.epoch_time(rt4)
  - def: ts = r.expr([t1, t2, t3, t4])

  # We run into double precision with the first one
  - rb: ((t2 - t1) * 1000).do{|x| (x > 0.99) & (x < 1.01)}
    py: ((t2 - t1) * 1000).do(lambda x:(x > 0.99) & (x < 1.01))
    js: t2.sub(t1).mul(1000).do(r.row.gt(0.99).and(r.row.lt(1.01)))
    ot: true
  - cd: t3 - t1
    js: t3.sub(t1)
    ot: 1
  - cd: t4 - t1
    js: t4.sub(t1)
    ot: 1000000000

  - rb: ((t1 - t2) * 1000).do{|x| (x < -0.99) & (x > -1.01)}
    py: ((t1 - t2) * 1000).do(lambda x:(x < -0.99) & (x > -1.01))
    js: t1.sub(t2).mul(1000).do(r.row.lt(-0.99).and(r.row.gt(-1.01)))
    ot: true
  - cd: t1 - t3
    js: t1.sub(t3)
    ot: -1
  - cd: t1 - t4
    js: t1.sub(t4)
    ot: -1000000000

  - rb: ts.map{|x| t1 + (x - t1)}.map{|x| x.to_epoch_time}
    py: ts.map(lambda x:t1 + (x - t1)).map(lambda x:x.to_epoch_time())
    js: ts.map(t1.add(r.row.sub(t1))).map(r.row.toEpochTime())
    ot: ([rt1, rt2, rt3, rt4])
  - rb: ts.map{|x| (t1 + x) - t1}.map{|x| x.to_epoch_time}
    py: ts.map(lambda x:(t1 + x) - t1).map(lambda x:x.to_epoch_time())
    js: ts.map(t1.add(r.row).sub(t1)).map(r.row.toEpochTime())
    ot: err("RqlRuntimeError", "Expected type NUMBER but found PTYPE<TIME>.", [])
  - rb: ts.map{|x| t1 - (t1 - x)}.map{|x| x.to_epoch_time}
    py: ts.map(lambda x:t1 - (t1 - x)).map(lambda x:x.to_epoch_time())
    js: ts.map(t1.sub(t1.sub(r.row))).map(r.row.toEpochTime())
    ot: ([rt1, rt2, rt3, rt4])

  - rb: ts.map{|x| ts.map{|y| [x < y, x <= y, x.eq(y), x.ne(y), x >= y, x > y]}}
    py: ts.map(lambda x:ts.map(lambda y:[x < y, x <= y, x == y, x != y, x >= y, x > y]))
    js: ts.map(function(x) { return ts.map(function(y) { return [x.lt(y), x.le(y), x.eq(y), x.ne(y), x.ge(y), x.gt(y)]; }); })
    ot: ([[[false, true,  true,  false, true,  false],
           [true,  true,  false, true,  false, false],
           [true,  true,  false, true,  false, false],
           [true,  true,  false, true,  false, false]],
          [[false, false, false, true,  true,  true],
           [false, true,  true,  false, true,  false],
           [true,  true,  false, true,  false, false],
           [true,  true,  false, true,  false, false]],
          [[false, false, false, true,  true,  true],
           [false, false, false, true,  true,  true],
           [false, true,  true,  false, true,  false],
           [true,  true,  false, true,  false, false]],
          [[false, false, false, true,  true,  true],
           [false, false, false, true,  true,  true],
           [false, false, false, true,  true,  true],
           [false, true,  true,  false, true,  false]]])

  - def:
      rb: datum_types = r([nil, true, false, 1, "1", [1], {"1" => 1}])
      py: datum_types = r.expr([None, true, false, 1, "1", [1], {"1":1}])
      js: datum_types = r([null, true, false, 1, "1", [1], {"1":1}])

# Test comparisons, from both directions (there was a problem where
# the directions had different behavior).
  - rb: datum_types.map{|x| [[x, t1], [t1, x]].map{|xy| xy[0].do{|x| xy[1].do{|y| [x < y, x <= y, x.eq(y), x.ne(y), x >= y, x > y]}}}}
    py: datum_types.map(lambda x:r.expr([[x, t1], [t1, x]]).map(lambda xy:xy[0].do(lambda x:xy[1].do(lambda y:[x < y, x <= y, x == y, x != y, x >= y, x > y]))))
    js: datum_types.map(function(x) { return r([[x, t1], [t1, x]]).map(function(xy) { return xy.nth(0).do(function(x) { return xy.nth(1).do(function(y) { return [x.lt(y), x.le(y), x.eq(y), x.ne(y), x.ge(y), x.gt(y)]; }); }); }); })
    ot: ([[[true,  true,  false, true,  false, false],
           [false, false, false, true,  true,  true]],
          [[true,  true,  false, true,  false, false],
           [false, false, false, true,  true,  true]],
          [[true,  true,  false, true,  false, false],
           [false, false, false, true,  true,  true]],
          [[true,  true,  false, true,  false, false],
           [false, false, false, true,  true,  true]],
          [[true,  true,  false, true,  false, false],
           [false, false, false, true,  true,  true]],
          [[true,  true,  false, true,  false, false],
           [false, false, false, true,  true,  true]],
          [[true,  true,  false, true,  false, false],
           [false, false, false, true,  true,  true]]])

  - rb: ts.map{|a| ts.map{|b| ts.map{|c| b.during(a, c)}}}
    py: ts.map(lambda a:ts.map(lambda b:ts.map(lambda c:b.during(a, c))))
    js: ts.map(function(a) { return ts.map(function(b) { return ts.map(function(c) { return b.during(a, c); }); }); })
    ot: ([[[false, true,  true,  true],
           [false, false, true,  true],
           [false, false, false, true],
           [false, false, false, false]],
          [[false, false, false, false],
           [false, false, true,  true],
           [false, false, false, true],
           [false, false, false, false]],
          [[false, false, false, false],
           [false, false, false, false],
           [false, false, false, true],
           [false, false, false, false]],
          [[false, false, false, false],
           [false, false, false, false],
           [false, false, false, false],
           [false, false, false, false]]])

  - rb: ts.map{|a| ts.map{|b| ts.map{|c| b.during(a, c, :left_bound => :open)}}}
    py: ts.map(lambda a:ts.map(lambda b:ts.map(lambda c:b.during(a, c, left_bound='open'))))
    js: ts.map(function(a) { return ts.map(function(b) { return ts.map(function(c) { return b.during(a, c, {leftBound:'open'}); }); }); })
    ot: ([[[false, false, false, false],
           [false, false, true,  true],
           [false, false, false, true],
           [false, false, false, false]],
          [[false, false, false, false],
           [false, false, false, false],
           [false, false, false, true],
           [false, false, false, false]],
          [[false, false, false, false],
           [false, false, false, false],
           [false, false, false, false],
           [false, false, false, false]],
          [[false, false, false, false],
           [false, false, false, false],
           [false, false, false, false],
           [false, false, false, false]]])

  - rb: ts.map{|a| ts.map{|b| ts.map{|c| b.during(a, c, :right_bound => :closed)}}}
    py: ts.map(lambda a:ts.map(lambda b:ts.map(lambda c:b.during(a, c, right_bound='closed'))))
    js: ts.map(function(a) { return ts.map(function(b) { return ts.map(function(c) { return b.during(a, c, {rightBound:'closed'}); }); }); })
    ot: ([[[true,  true,  true,  true],
           [false, true,  true,  true],
           [false, false, true,  true],
           [false, false, false, true]],
          [[false, false, false, false],
           [false, true,  true,  true],
           [false, false, true,  true],
           [false, false, false, true]],
          [[false, false, false, false],
           [false, false, false, false],
           [false, false, true,  true],
           [false, false, false, true]],
          [[false, false, false, false],
           [false, false, false, false],
           [false, false, false, false],
           [false, false, false, true]]])

  - rb: ts.map{|a| ts.map{|b| ts.map{|c| b.during(a, c, :left_bound => :open, :right_bound => :closed)}}}
    py: ts.map(lambda a:ts.map(lambda b:ts.map(lambda c:b.during(a, c, left_bound='open', right_bound='closed'))))
    js: ts.map(function(a) { return ts.map(function(b) { return ts.map(function(c) { return b.during(a, c, {leftBound:'open', rightBound:'closed'}); }); }); })
    ot: ([[[false, false, false, false],
           [false, true,  true,  true],
           [false, false, true,  true],
           [false, false, false, true]],
          [[false, false, false, false],
           [false, false, false, false],
           [false, false, true,  true],
           [false, false, false, true]],
          [[false, false, false, false],
           [false, false, false, false],
           [false, false, false, false],
           [false, false, false, true]],
          [[false, false, false, false],
           [false, false, false, false],
           [false, false, false, false],
           [false, false, false, false]]])

  - rb: ts.map{|x| x.date + x.time_of_day}.map{|x| x.to_epoch_time}
    py: ts.map(lambda x:x.date() + x.time_of_day()).map(lambda x:x.to_epoch_time())
    js: ts.map(r.row.date().add(r.row.timeOfDay())).map(r.row.toEpochTime())
    ot: rts

  # Test time interaction with r.js
  - rb: r.epoch_time(rt1).do(r.js("(function(data){return data})")).to_epoch_time()
    py: r.epoch_time(rt1).do(r.js("(function(data){return data})")).to_epoch_time()
    js: r.epoch_time(rt1).do(r.js("(function(data){return data})")).toEpochTime()
    ot: rt1

  - rb: r.do(r.js("new Date('2012-08-01')")).to_iso8601()
    py: r.do(r.js("new Date('2012-08-01')")).to_iso8601()
    js: r.do(r.js("new Date('2012-08-01')")).toISO8601()
    ot: ("2012-08-01T00:00:00+00:00")

  - rb: r.do(r.js("(function(x){doc = new Object(); doc.date = new Date('2012-08-01'); return doc;})"))["date"].to_iso8601()
    py: r.do(r.js("(function(x){doc = new Object(); doc.date = new Date('2012-08-01'); return doc;})"))["date"].to_iso8601()
    js: r.do(r.js("(function(x){doc = new Object(); doc.date = new Date('2012-08-01'); return doc;})"))("date").toISO8601()
    ot: ("2012-08-01T00:00:00+00:00")
