Repository: Qiskit/qiskit

Issue:
Pulse Schedules can be shifted by non-integer values.
<!-- ⚠️ If you do not respect this template, your issue will be closed -->
<!-- ⚠️ Make sure to browse the opened and closed issues -->

### Information

- **Qiskit Terra version**:
- **Python version**:
- **Operating system**:

### What is the current behavior?
A pulse schedule will accept a shift by a non-integer value. Also shifting and unshifting a schedule will raise an error.


### Steps to reproduce the problem
```python
from qiskit import pulse
sched = pulse.Schedule()
sched = sched.append(pulse.Delay(10, pulse.DriveChannel(0)))
print(sched)
print(sched << 1.1)
```


### What is the expected behavior?
This should raise an exception.

### Suggested solutions





Discussion:

Resolving patch:
diff --git a/qiskit/pulse/instructions/instruction.py b/qiskit/pulse/instructions/instruction.py
--- a/qiskit/pulse/instructions/instruction.py
+++ b/qiskit/pulse/instructions/instruction.py
@@ -63,6 +63,9 @@ def __init__(self,
             PulseError: If duration is negative.
         """
         self._command = None
+        if isinstance(duration, (float, np.float)):
+            raise PulseError("Instruction duration was passed as a float. "
+                             "Please replace with an integer.")
         if not isinstance(duration, (int, np.integer)):
             warnings.warn("Commands have been deprecated. Use `qiskit.pulse.instructions` instead.",
                           DeprecationWarning)
diff --git a/qiskit/pulse/schedule.py b/qiskit/pulse/schedule.py
--- a/qiskit/pulse/schedule.py
+++ b/qiskit/pulse/schedule.py
@@ -71,6 +71,9 @@ def __init__(self, *schedules: List[Union[ScheduleComponent, Tuple[int, Schedule
             # convert to tuple
             sched_pair = tuple(sched_pair)
             insert_time, sched = sched_pair
+            if not isinstance(insert_time, int):
+                raise PulseError("Schedule start time was a non-integer. Please cast times to "
+                                 "integers.")
             sched_timeslots = sched.timeslots
             if insert_time:
                 sched_timeslots = sched_timeslots.shift(insert_time)
@@ -232,7 +235,12 @@ def insert(self, start_time: int, schedule: ScheduleComponent,
             start_time: Time to insert the schedule.
             schedule: Schedule to insert.
             name: Name of the new schedule. Defaults to the name of self.
+
+        Raises:
+            PulseError: If start_time is not an integer.
         """
+        if not isinstance(start_time, int):
+            raise PulseError("Schedules can only be inserted at integer times.")
         if name is None:
             name = self.name
         new_sched = Schedule(name=name)


Test patch:
diff --git a/test/python/pulse/test_schedule.py b/test/python/pulse/test_schedule.py
--- a/test/python/pulse/test_schedule.py
+++ b/test/python/pulse/test_schedule.py
@@ -419,6 +419,34 @@ def test_parametric_commands_in_sched(self):
         self.assertEqual(sched.duration, 1525)
         self.assertTrue('sigma' in sched.instructions[0][1].pulse.parameters)
 
+    def test_negative_time_raises(self):
+        """Test that a negative time will raise an error."""
+        sched = Schedule()
+        sched += Delay(1, DriveChannel(0))
+        with self.assertRaises(PulseError):
+            sched.shift(-10)
+
+    def test_shift_float_time_raises(self):
+        """Test that a floating time will raise an error with shift."""
+        sched = Schedule()
+        sched += Delay(1, DriveChannel(0))
+        with self.assertRaises(PulseError):
+            sched.shift(0.1)
+
+    def test_insert_float_time_raises(self):
+        """Test that a floating time will raise an error with insert."""
+        sched = Schedule()
+        sched += Delay(1, DriveChannel(0))
+        with self.assertRaises(PulseError):
+            sched.insert(10.1, sched)
+
+    def test_shift_unshift(self):
+        """Test shift and then unshifting of schedule"""
+        reference_sched = Schedule()
+        reference_sched += Delay(10, DriveChannel(0))
+        shifted_sched = reference_sched.shift(10).shift(-10)
+        self.assertEqual(shifted_sched, reference_sched)
+
 
 class TestDelay(BaseTestSchedule):
     """Test Delay Instruction"""