diff --git a/holoviews/core/util.py b/holoviews/core/util.py
index 55712daa54..9223f01077 100644
--- a/holoviews/core/util.py
+++ b/holoviews/core/util.py
@@ -16,8 +16,11 @@
 except:
     from collections import OrderedDict
 
+datetime_types = (np.datetime64, dt.datetime)
+
 try:
     import pandas as pd # noqa (optional import)
+    datetime_types = datetime_types + (pd.tslib.Timestamp,)
 except ImportError:
     pd = None
 
@@ -493,13 +496,13 @@ def max_extents(extents, zrange=False):
         for lidx, uidx in inds:
             lower = [v for v in arr[lidx] if v is not None]
             upper = [v for v in arr[uidx] if v is not None]
-            if lower and isinstance(lower[0], np.datetime64):
+            if lower and isinstance(lower[0], datetime_types):
                 extents[lidx] = np.min(lower)
             elif any(isinstance(l, basestring) for l in lower):
                 extents[lidx] = np.sort(lower)[0]
             elif lower:
                 extents[lidx] = np.nanmin(lower)
-            if upper and isinstance(upper[0], np.datetime64):
+            if upper and isinstance(upper[0], datetime_types):
                 extents[uidx] = np.max(upper)
             elif any(isinstance(u, basestring) for u in upper):
                 extents[uidx] = np.sort(upper)[-1]
diff --git a/holoviews/plotting/bokeh/element.py b/holoviews/plotting/bokeh/element.py
index 1312210319..0365ea3d4c 100644
--- a/holoviews/plotting/bokeh/element.py
+++ b/holoviews/plotting/bokeh/element.py
@@ -281,12 +281,12 @@ def _axes_props(self, plots, subplots, element, ranges):
                 if plot.yaxis[0].axis_label == xlabel:
                     plot_ranges['x_range'] = plot.y_range
 
-        if el.get_dimension_type(0) is np.datetime64:
+        if el.get_dimension_type(0) in util.datetime_types:
             x_axis_type = 'datetime'
         else:
             x_axis_type = 'log' if self.logx else 'auto'
 
-        if len(dims) > 1 and el.get_dimension_type(1) is np.datetime64:
+        if len(dims) > 1 and el.get_dimension_type(1) in util.datetime_types:
             y_axis_type = 'datetime'
         else:
             y_axis_type = 'log' if self.logy else 'auto'
@@ -294,66 +294,25 @@ def _axes_props(self, plots, subplots, element, ranges):
         # Get the Element that determines the range and get_extents
         range_el = el if self.batched and not isinstance(self, OverlayPlot) else element
         l, b, r, t = self.get_extents(range_el, ranges)
-
-        categorical = False
-        if not 'x_range' in plot_ranges:
-            if 'x_range' in ranges:
-                plot_ranges['x_range'] = ranges['x_range']
-            else:
-                low, high = (b, t) if self.invert_axes else (l, r)
-                if x_axis_type == 'datetime':
-                    low = convert_datetime(low)
-                    high = convert_datetime(high)
-                elif any(isinstance(x, util.basestring) for x in (low, high)):
-                    plot_ranges['x_range'] = FactorRange()
-                    categorical = True
-                elif low == high and low is not None:
-                    offset = low*0.1 if low else 0.5
-                    low -= offset
-                    high += offset
-                if not categorical and all(x is not None and np.isfinite(x) for x in (low, high)):
-                    plot_ranges['x_range'] = [low, high]
-
-        if self.invert_xaxis:
-            x_range = plot_ranges['x_range']
-            if isinstance(x_range, Range1d):
-                plot_ranges['x_range'] = x_range.__class__(start=x_range.end,
-                                                           end=x_range.start)
-            elif not isinstance(x_range, (Range, FactorRange)):
-                plot_ranges['x_range'] = x_range[::-1]
-
-        categorical = False
-        if not 'y_range' in plot_ranges:
-            if 'y_range' in ranges:
-                plot_ranges['y_range'] = ranges['y_range']
-            else:
-                low, high = (l, r) if self.invert_axes else (b, t)
-                if y_axis_type == 'datetime':
-                    low = convert_datetime(low)
-                    high = convert_datetime(high)
-                elif any(isinstance(y, util.basestring) for y in (low, high)):
-                    plot_ranges['y_range'] = FactorRange()
-                    categorical = True
-                elif low == high and low is not None:
-                    offset = low*0.1 if low else 0.5
-                    low -= offset
-                    high += offset
-                if not categorical and all(y is not None and np.isfinite(y) for y in (low, high)):
-                    plot_ranges['y_range'] = [low, high]
-
-        if self.invert_yaxis:
-            yrange = plot_ranges['y_range']
-            if isinstance(yrange, Range1d):
-                plot_ranges['y_range'] = yrange.__class__(start=yrange.end,
-                                                          end=yrange.start)
-            elif not isinstance(yrange, (Range, FactorRange)):
-                plot_ranges['y_range'] = yrange[::-1]
+        if self.invert_axes:
+            l, b, r, t = b, l, t, r
 
         categorical = any(self.traverse(lambda x: x._categorical))
-        if categorical:
-            x_axis_type, y_axis_type = 'auto', 'auto'
+        categorical_x = any(isinstance(x, util.basestring) for x in (l, r))
+        categorical_y = any(isinstance(y, util.basestring) for y in (b, t))
+
+        if categorical or categorical_x:
+            x_axis_type = 'auto'
             plot_ranges['x_range'] = FactorRange()
+        elif 'x_range' not in plot_ranges:
+            plot_ranges['x_range'] = Range1d()
+
+        if categorical or categorical_y:
+            y_axis_type = 'auto'
             plot_ranges['y_range'] = FactorRange()
+        elif 'y_range' not in plot_ranges:
+            plot_ranges['y_range'] = Range1d()
+
         return (x_axis_type, y_axis_type), (xlabel, ylabel, zlabel), plot_ranges
 
 
@@ -517,44 +476,37 @@ def _update_ranges(self, element, ranges):
         x_range = self.handles['x_range']
         y_range = self.handles['y_range']
 
+        l, b, r, t = None, None, None, None
         if any(isinstance(r, Range1d) for r in [x_range, y_range]):
             l, b, r, t = self.get_extents(element, ranges)
             if self.invert_axes:
                 l, b, r, t = b, l, t, r
 
-        if any(isinstance(r, FactorRange) for r in [x_range, y_range]):
+        xfactors, yfactors = None, None
+        if any(isinstance(ax_range, FactorRange) for ax_range in [x_range, y_range]):
             xfactors, yfactors = self._get_factors(element)
-
-        if isinstance(x_range, Range1d):
-            if l == r and l is not None:
-                offset = abs(l*0.1 if l else 0.5)
-                l -= offset
-                r += offset
-
-            if self.invert_xaxis: l, r = r, l
-            if l is not None and (isinstance(l, np.datetime64) or np.isfinite(l)):
-                plot.x_range.start = l
-            if r is not None and (isinstance(r, np.datetime64) or np.isfinite(r)):
-                plot.x_range.end   = r
-        elif isinstance(x_range, FactorRange):
-            xfactors = list(xfactors)
-            if self.invert_xaxis: xfactors = xfactors[::-1]
-            x_range.factors = xfactors
-
-        if isinstance(plot.y_range, Range1d):
-            if b == t and b is not None:
-                offset = abs(b*0.1 if b else 0.5)
-                b -= offset
-                t += offset
-            if self.invert_yaxis: b, t = t, b
-            if b is not None and (isinstance(l, np.datetime64) or np.isfinite(b)):
-                plot.y_range.start = b
-            if t is not None and (isinstance(l, np.datetime64) or np.isfinite(t)):
-                plot.y_range.end   = t
-        elif isinstance(y_range, FactorRange):
-            yfactors = list(yfactors)
-            if self.invert_yaxis: yfactors = yfactors[::-1]
-            y_range.factors = yfactors
+        self._update_range(x_range, l, r, xfactors, self.invert_xaxis)
+        self._update_range(y_range, b, t, yfactors, self.invert_yaxis)
+
+
+    def _update_range(self, axis_range, low, high, factors, invert):
+        if isinstance(axis_range, Range1d):
+            if (low == high and low is not None and
+                not isinstance(high, util.datetime_types)):
+                offset = abs(low*0.1 if low else 0.5)
+                low -= offset
+                high += offset
+            if invert: low, high = high, low
+            if low is not None and (isinstance(low, util.datetime_types)
+                                    or np.isfinite(low)):
+                axis_range.start = low
+            if high is not None and (isinstance(high, util.datetime_types)
+                                     or np.isfinite(high)):
+                axis_range.end = high
+        elif isinstance(axis_range, FactorRange):
+            factors = list(factors)
+            if invert: factors = factors[::-1]
+            axis_range.factors = factors
 
 
     def _categorize_data(self, data, cols, dims):
diff --git a/holoviews/plotting/plot.py b/holoviews/plotting/plot.py
index 0d2eb9ac3a..338683de1a 100644
--- a/holoviews/plotting/plot.py
+++ b/holoviews/plotting/plot.py
@@ -709,8 +709,14 @@ def get_extents(self, view, ranges):
         if getattr(self, 'shared_axes', False) and self.subplot:
             return util.max_extents([range_extents, extents], self.projection == '3d')
         else:
-            return tuple(l1 if l2 is None or not np.isfinite(l2) else
-                         l2 for l1, l2 in zip(range_extents, extents))
+            max_extent = []
+            for l1, l2 in zip(range_extents, extents):
+                if (isinstance(l2, util.datetime_types)
+                    or (l2 is not None and np.isfinite(l2))):
+                    max_extent.append(l2)
+                else:
+                    max_extent.append(l1)
+            return tuple(max_extent)
 
 
     def _get_axis_labels(self, dimensions, xlabel=None, ylabel=None, zlabel=None):
diff --git a/tests/testplotinstantiation.py b/tests/testplotinstantiation.py
index f2b16c61bc..fe2a403f85 100644
--- a/tests/testplotinstantiation.py
+++ b/tests/testplotinstantiation.py
@@ -13,6 +13,7 @@
 import numpy as np
 from holoviews import (Dimension, Overlay, DynamicMap, Store,
                        NdOverlay, GridSpace, HoloMap, Layout)
+from holoviews.core.util import pd
 from holoviews.element import (Curve, Scatter, Image, VLine, Points,
                                HeatMap, QuadMesh, Spikes, ErrorBars,
                                Scatter3D, Path, Polygons, Bars, Text,
@@ -142,6 +143,46 @@ def test_points_non_numeric_size_warning(self):
                    'cannot use to scale Points size.\n' % plot.name)
         self.assertEqual(log_msg, warning)
 
+    def test_curve_datetime64(self):
+        dates = [np.datetime64(dt.datetime(2016,1,i)) for i in range(1, 11)]
+        curve = Curve((dates, np.random.rand(10)))
+        plot = mpl_renderer.get_plot(curve)
+        self.assertEqual(plot.handles['axis'].get_xlim(), (735964.0, 735973.0))
+
+    def test_curve_pandas_timestamps(self):
+        if not pd:
+            raise SkipError("Pandas not available")
+        dates = pd.date_range('2016-01-01', '2016-01-10', freq='D')
+        curve = Curve((dates, np.random.rand(10)))
+        plot = mpl_renderer.get_plot(curve)
+        self.assertEqual(plot.handles['axis'].get_xlim(), (735964.0, 735973.0))
+
+    def test_curve_dt_datetime(self):
+        dates = [dt.datetime(2016,1,i) for i in range(1, 11)]
+        curve = Curve((dates, np.random.rand(10)))
+        plot = mpl_renderer.get_plot(curve)
+        self.assertEqual(plot.handles['axis'].get_xlim(), (735964.0, 735973.0))
+
+    def test_curve_heterogeneous_datetime_types_overlay(self):
+        dates64 = [np.datetime64(dt.datetime(2016,1,i)) for i in range(1, 11)]
+        dates = [dt.datetime(2016,1,i) for i in range(2, 12)]
+        curve_dt64 = Curve((dates64, np.random.rand(10)))
+        curve_dt = Curve((dates, np.random.rand(10)))
+        plot = mpl_renderer.get_plot(curve_dt*curve_dt64)
+        self.assertEqual(plot.handles['axis'].get_xlim(), (735964.0, 735974.0))
+
+    def test_curve_heterogeneous_datetime_types_with_pd_overlay(self):
+        if not pd:
+            raise SkipError("Pandas not available")
+        dates_pd = pd.date_range('2016-01-04', '2016-01-13', freq='D')
+        dates64 = [np.datetime64(dt.datetime(2016,1,i)) for i in range(1, 11)]
+        dates = [dt.datetime(2016,1,i) for i in range(2, 12)]
+        curve_dt64 = Curve((dates64, np.random.rand(10)))
+        curve_dt = Curve((dates, np.random.rand(10)))
+        curve_pd = Curve((dates_pd, np.random.rand(10)))
+        plot = mpl_renderer.get_plot(curve_dt*curve_dt64*curve_pd)
+        self.assertEqual(plot.handles['axis'].get_xlim(), (735964.0, 735976.0))
+
 
 
 class TestBokehPlotInstantiation(ComparisonTestCase):
@@ -557,6 +598,51 @@ def test_box_whisker_datetime(self):
         self.assertTrue(cds.data['Date'][0] in formatted for cds in
                         plot.state.select(ColumnDataSource))
 
+    def test_curve_datetime64(self):
+        dates = [np.datetime64(dt.datetime(2016,1,i)) for i in range(1, 11)]
+        curve = Curve((dates, np.random.rand(10)))
+        plot = bokeh_renderer.get_plot(curve)
+        self.assertEqual(plot.handles['x_range'].start, np.datetime64(dt.datetime(2016, 1, 1)))
+        self.assertEqual(plot.handles['x_range'].end, np.datetime64(dt.datetime(2016, 1, 10)))
+
+    def test_curve_pandas_timestamps(self):
+        if not pd:
+            raise SkipError("Pandas not available")
+        dates = pd.date_range('2016-01-01', '2016-01-10', freq='D')
+        curve = Curve((dates, np.random.rand(10)))
+        plot = bokeh_renderer.get_plot(curve)
+        self.assertEqual(plot.handles['x_range'].start, np.datetime64(dt.datetime(2016, 1, 1)))
+        self.assertEqual(plot.handles['x_range'].end, np.datetime64(dt.datetime(2016, 1, 10)))
+
+    def test_curve_dt_datetime(self):
+        dates = [dt.datetime(2016,1,i) for i in range(1, 11)]
+        curve = Curve((dates, np.random.rand(10)))
+        plot = bokeh_renderer.get_plot(curve)
+        self.assertEqual(plot.handles['x_range'].start, np.datetime64(dt.datetime(2016, 1, 1)))
+        self.assertEqual(plot.handles['x_range'].end, np.datetime64(dt.datetime(2016, 1, 10)))
+
+    def test_curve_heterogeneous_datetime_types_overlay(self):
+        dates64 = [np.datetime64(dt.datetime(2016,1,i)) for i in range(1, 11)]
+        dates = [dt.datetime(2016,1,i) for i in range(2, 12)]
+        curve_dt64 = Curve((dates64, np.random.rand(10)))
+        curve_dt = Curve((dates, np.random.rand(10)))
+        plot = bokeh_renderer.get_plot(curve_dt*curve_dt64)
+        self.assertEqual(plot.handles['x_range'].start, np.datetime64(dt.datetime(2016, 1, 1)))
+        self.assertEqual(plot.handles['x_range'].end, np.datetime64(dt.datetime(2016, 1, 11)))
+
+    def test_curve_heterogeneous_datetime_types_with_pd_overlay(self):
+        if not pd:
+            raise SkipError("Pandas not available")
+        dates_pd = pd.date_range('2016-01-04', '2016-01-13', freq='D')
+        dates64 = [np.datetime64(dt.datetime(2016,1,i)) for i in range(1, 11)]
+        dates = [dt.datetime(2016,1,i) for i in range(2, 12)]
+        curve_dt64 = Curve((dates64, np.random.rand(10)))
+        curve_dt = Curve((dates, np.random.rand(10)))
+        curve_pd = Curve((dates_pd, np.random.rand(10)))
+        plot = bokeh_renderer.get_plot(curve_dt*curve_dt64*curve_pd)
+        self.assertEqual(plot.handles['x_range'].start, np.datetime64(dt.datetime(2016, 1, 1)))
+        self.assertEqual(plot.handles['x_range'].end, np.datetime64(dt.datetime(2016, 1, 13)))
+
 
 class TestPlotlyPlotInstantiation(ComparisonTestCase):