diff --git a/src/cosmology.c b/src/cosmology.c
index f33a41e1b3370ad8f6c84bbacfdcaa87c31558aa..3302bdcb519c2bfcb34d03b97508edacb09928dd 100644
--- a/src/cosmology.c
+++ b/src/cosmology.c
@@ -28,6 +28,44 @@
 /* Some standard headers */
 #include <math.h>
 
+/* Local headers */
+#include "inline.h"
+
+#ifdef HAVE_LIBGSL
+#include <gsl/gsl_integration.h>
+#endif
+
+const int cosmology_table_length = 10000;
+const size_t GSL_workspace_size = 10000;
+
+/**
+ * @brief Compute \f$ E(z) \f$.
+ */
+static INLINE double E(double Or, double Om, double Ok, double Ol,
+                       double a_inv) {
+
+  return sqrt(Or * a_inv * a_inv * a_inv * a_inv + Om * a_inv * a_inv * a_inv +
+              Ok * a_inv * a_inv + Ol);
+}
+
+double cosmology_get_time(const struct cosmology *c, double a) {
+
+  const double log_a = log(a);
+
+  /* Position in the table */
+  const double x =
+      ((log_a - c->log_a_begin) / (c->log_a_end - c->log_a_begin)) *
+      cosmology_table_length;
+  const int i =
+      ((int)x >= cosmology_table_length) ? cosmology_table_length - 1 : (int)x;
+
+  if (i <= 1)
+    return c->time_interp_table_offset + x * c->time_interp_table[0];
+  else
+    return c->time_interp_table_offset + c->time_interp_table[i - 1] +
+           (c->time_interp_table[i] - c->time_interp_table[i - 1]) * (x - i);
+}
+
 /**
  * @brief Update the cosmological parameters to the current simulation time.
  *
@@ -48,17 +86,129 @@ void cosmology_update(struct cosmology *c, const struct engine *e) {
   /* E(z) */
   const double Omega_r = c->Omega_r;
   const double Omega_m = c->Omega_m;
+  const double Omega_k = c->Omega_k;
   const double Omega_l = c->Omega_lambda;
+  const double E_z = E(Omega_r, Omega_m, Omega_k, Omega_l, a_inv);
+
+  /* H(z) */
+  c->H = c->H0 * E_z;
+
+  /* Time since Big Bang */
+  c->time = cosmology_get_time(c, a);
+}
+
+void cosmology_init_tables(struct cosmology *c) {
+
+  const ticks tic = getticks();
+
+#ifdef HAVE_LIBGSL
+
+  /* Retrieve some constants */
+  const double a_begin = c->a_begin;
+  const double Omega_r = c->Omega_r;
+  const double Omega_m = c->Omega_m;
   const double Omega_k = c->Omega_k;
+  const double Omega_l = c->Omega_lambda;
+  const double H0 = c->H0;
 
-  const double E_z2 = Omega_r * a_inv * a_inv * a_inv * a_inv +
-                      Omega_m * a_inv * a_inv * a_inv +
-                      Omega_k * a_inv * a_inv + Omega_l;
+  /* Allocate memory for the interpolation tables */
+  c->drift_fac_interp_table = malloc(cosmology_table_length * sizeof(double));
+  c->grav_kick_fac_interp_table =
+      malloc(cosmology_table_length * sizeof(double));
+  c->time_interp_table = malloc(cosmology_table_length * sizeof(double));
 
-  const double E_z = sqrt(E_z2);
+  /* Define the integrands we need */
 
-  /* H(z) */
-  c->H = c->H0 * E_z;
+  /* dt / a^2 */
+  double drift_integrand(double a, void *param) {
+
+    const double a_inv = 1. / a;
+    const double E_z = E(Omega_r, Omega_m, Omega_k, Omega_l, a_inv);
+    const double H = H0 * E_z;
+
+    return (1. / H) * a_inv * a_inv * a_inv;
+  }
+
+  /* dt / a */
+  double gravity_kick_integrand(double a, void *param) {
+
+    const double a_inv = 1. / a;
+    const double E_z = E(Omega_r, Omega_m, Omega_k, Omega_l, a_inv);
+    const double H = H0 * E_z;
+
+    return (1. / H) * a_inv * a_inv;
+  }
+
+  /* dt */
+  double time_integrand(double a, void *param) {
+
+    const double a_inv = 1. / a;
+    const double E_z = E(Omega_r, Omega_m, Omega_k, Omega_l, a_inv);
+    const double H = H0 * E_z;
+
+    return (1. / H) * a_inv;
+  }
+
+  /* Prepare a table of scale factors for the integral bounds */
+  const double delta_a =
+      (c->log_a_end - c->log_a_begin) / cosmology_table_length;
+  double *a_table = malloc(cosmology_table_length * sizeof(double));
+  for (int i = 0; i < cosmology_table_length; i++)
+    a_table[i] = exp(c->log_a_begin + delta_a * (i + 1));
+
+  /* Initalise the GSL workspace */
+  gsl_integration_workspace *space =
+      gsl_integration_workspace_alloc(GSL_workspace_size);
+
+  double result, abserr;
+
+  /* Integrate the drift factor \int_{a_begin}^{a_table[i]} dt/a^2 */
+  gsl_function F = {&drift_integrand, NULL};
+  for (int i = 0; i < cosmology_table_length; i++) {
+    gsl_integration_qag(&F, a_begin, a_table[i], 0, 1.0e-10, GSL_workspace_size,
+                        GSL_INTEG_GAUSS61, space, &result, &abserr);
+
+    /* Store result */
+    c->drift_fac_interp_table[i] = result;
+  }
+
+  /* Integrate the kick factor \int_{a_begin}^{a_table[i]} dt/a */
+  F.function = &gravity_kick_integrand;
+  for (int i = 0; i < cosmology_table_length; i++) {
+    gsl_integration_qag(&F, a_begin, a_table[i], 0, 1.0e-10, GSL_workspace_size,
+                        GSL_INTEG_GAUSS61, space, &result, &abserr);
+
+    /* Store result */
+    c->grav_kick_fac_interp_table[i] = result;
+  }
+
+  /* Integrate the time \int_{a_begin}^{a_table[i]} dt */
+  F.function = &time_integrand;
+  for (int i = 0; i < cosmology_table_length; i++) {
+    gsl_integration_qag(&F, a_begin, a_table[i], 0, 1.0e-10, GSL_workspace_size,
+                        GSL_INTEG_GAUSS61, space, &result, &abserr);
+
+    /* Store result */
+    c->time_interp_table[i] = result;
+  }
+
+  /* Integrate the time \int_{0}^{a_begin} dt */
+  gsl_integration_qag(&F, 0., a_begin, 0, 1.0e-10, GSL_workspace_size,
+                      GSL_INTEG_GAUSS61, space, &result, &abserr);
+  c->time_interp_table_offset = result;
+
+  /* Free the workspace and temp array */
+  gsl_integration_workspace_free(space);
+  free(a_table);
+
+#else
+
+  error("Code not compiled with GSL. Can't compute cosmology integrals.");
+
+#endif
+
+  message("took %.3f %s.", clocks_from_ticks(getticks() - tic),
+          clocks_getunit());
 }
 
 void cosmology_init(const struct swift_params *params,
@@ -75,6 +225,8 @@ void cosmology_init(const struct swift_params *params,
   /* Read the start and end of the simulation */
   c->a_begin = parser_get_param_double(params, "Cosmology:a_begin");
   c->a_end = parser_get_param_double(params, "Cosmology:a_end");
+  c->log_a_begin = log(c->a_begin);
+  c->log_a_end = log(c->a_end);
 
   /* Construct derived quantities */
 
@@ -82,8 +234,9 @@ void cosmology_init(const struct swift_params *params,
   c->Omega_k = 1. - (c->Omega_m + c->Omega_r + c->Omega_lambda);
 
   /* Hubble constant in internal units */
-  const double km = 1.e5 / units_cgs_conversion_factor(us, UNIT_CONV_LENGTH); 
-  const double H0_cgs = 100. * c->h * (km / (1.e6 * phys_const->const_parsec)); /* s^-1 */
+  const double km = 1.e5 / units_cgs_conversion_factor(us, UNIT_CONV_LENGTH);
+  const double H0_cgs =
+      100. * c->h * (km / (1.e6 * phys_const->const_parsec)); /* s^-1 */
   c->H0 = H0_cgs * units_cgs_conversion_factor(us, UNIT_CONV_TIME);
 
   /* Set remaining variables to invalid values */
@@ -91,6 +244,14 @@ void cosmology_init(const struct swift_params *params,
   c->a = -1.;
   c->a_inv = -1;
   c->z = -1.;
+  c->time = -1.;
+
+  /* Initialise the interpolation tables */
+  c->drift_fac_interp_table = NULL;
+  c->grav_kick_fac_interp_table = NULL;
+  c->time_interp_table = NULL;
+  c->time_interp_table_offset = 0.;
+  cosmology_init_tables(c);
 }
 
 void cosmology_print(const struct cosmology *c) {
diff --git a/src/cosmology.h b/src/cosmology.h
index df8cea4ec91687d2ca4f49ed6a71db89a6eb6672..6029d2be42b3d8c27a613a20008d2a556d7f4b7e 100644
--- a/src/cosmology.h
+++ b/src/cosmology.h
@@ -42,10 +42,13 @@ struct cosmology {
   /*! Hubble constant at the current redshift (in internal units) */
   double H;
 
+  /*! Time (in internal units) since the Big Bang */
+  double time;
+
   /*! Starting expansion factor */
   double a_begin;
 
-  /*! Ending expansion factor */
+  /*! Final expansion factor */
   double a_end;
 
   /*! Reduced Hubble constant (H0 / (100km/s/Mpc)) */
@@ -68,6 +71,24 @@ struct cosmology {
 
   /*! Curvature density parameter */
   double Omega_k;
+
+  /*! Log of starting expansion factor */
+  double log_a_begin;
+
+  /*! Log of final expansion factor */
+  double log_a_end;
+
+  /*! Drift factor interpolation table */
+  double *drift_fac_interp_table;
+
+  /*! Kick factor interpolation table */
+  double *grav_kick_fac_interp_table;
+
+  /*! Time interpolation table */
+  double *time_interp_table;
+
+  /*! Time between Big Bang and first entry in the table */
+  double time_interp_table_offset;
 };
 
 void cosmology_update(struct cosmology *c, const struct engine *e);