diff --git a/include/bits/sys/stat.h b/include/bits/sys/stat.h
index 9f62d7ff4fcfe06ef0d3e6f09b16bee701341224..b9ae34fefc5b386a8c295b1607799de2a7a852e5 100644
--- a/include/bits/sys/stat.h
+++ b/include/bits/sys/stat.h
@@ -8,4 +8,7 @@
 #define S_ISIFO(mode) mode & S_IFMT == S_IFIFO
 #define S_ISLNK(mode) mode & S_IFMT == S_IFLNK
 
+#define st_atime st_atim.tv_sec
+#define st_mtime st_mtim.tv_sec
+
 #endif
diff --git a/include/bits/timespec.h b/include/bits/timespec.h
deleted file mode 100644
index 5f36eaa8cc3bc1c28db802742fa14398411aa169..0000000000000000000000000000000000000000
--- a/include/bits/timespec.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef _BITS_TIMESPEC_H
-#define _BITS_TIMESPEC_H
-
-typedef struct {
-    time_t tv_sec;
-    long tv_nsec;
-} timespec;
-
-#endif
diff --git a/src/platform/src/linux/mod.rs b/src/platform/src/linux/mod.rs
index 409440b0d6094cc7f637ca6ed97014b9767bf2ec..29c0de44a9ec666ca5d052838bccccac58016257 100644
--- a/src/platform/src/linux/mod.rs
+++ b/src/platform/src/linux/mod.rs
@@ -103,6 +103,10 @@ pub fn ftruncate(fildes: c_int, length: off_t) -> c_int {
     e(unsafe { syscall!(FTRUNCATE, fildes, length) }) as c_int
 }
 
+pub fn futimens(fd: c_int, times: *const timespec) -> c_int {
+    e(unsafe { syscall!(UTIMENSAT, fd, ptr::null::<c_char>(), times, 0) }) as c_int
+}
+
 pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char {
     if e(unsafe { syscall!(GETCWD, buf, size) }) == !0 {
         ptr::null_mut()
diff --git a/src/platform/src/redox/mod.rs b/src/platform/src/redox/mod.rs
index ef07ae16d8a2dd97f763ded3f01d8aa5cf6bbec8..f778d7665ea763b889b058a1b9712638d5bf23e3 100644
--- a/src/platform/src/redox/mod.rs
+++ b/src/platform/src/redox/mod.rs
@@ -246,9 +246,18 @@ pub fn fstat(fildes: c_int, buf: *mut stat) -> c_int {
                     (*buf).st_rdev = 0;
                     (*buf).st_size = redox_buf.st_size as off_t;
                     (*buf).st_blksize = redox_buf.st_blksize as blksize_t;
-                    (*buf).st_atim = redox_buf.st_atime as time_t;
-                    (*buf).st_mtim = redox_buf.st_mtime as time_t;
-                    (*buf).st_ctim = redox_buf.st_ctime as time_t;
+                    (*buf).st_atim = timespec {
+                        tv_sec: redox_buf.st_atime as time_t,
+                        tv_nsec: 0
+                    };
+                    (*buf).st_mtim = timespec {
+                        tv_sec: redox_buf.st_mtime as time_t,
+                        tv_nsec: 0
+                    };
+                    (*buf).st_ctim = timespec {
+                        tv_sec: redox_buf.st_ctime as time_t,
+                        tv_nsec: 0
+                    };
                 }
             }
             0
@@ -265,6 +274,14 @@ pub fn ftruncate(fd: c_int, len: off_t) -> c_int {
     e(syscall::ftruncate(fd as usize, len as usize)) as c_int
 }
 
+pub fn futimens(fd: c_int, times: *const timespec) -> c_int {
+    let times = [
+        unsafe { redox_timespec::from(&*times) },
+        unsafe { redox_timespec::from(&*times.offset(1)) }
+    ];
+    e(syscall::futimens(fd as usize, &times)) as c_int
+}
+
 pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char {
     let buf_slice = unsafe { slice::from_raw_parts_mut(buf as *mut u8, size as usize) };
     if e(syscall::getcwd(buf_slice)) == !0 {
diff --git a/src/platform/src/types.rs b/src/platform/src/types.rs
index 08a8a7262390af62eca78eee935f66a55a0e1f1f..6d4902ed2a5a2c68a73aad45f63ba18751324d28 100644
--- a/src/platform/src/types.rs
+++ b/src/platform/src/types.rs
@@ -112,14 +112,14 @@ pub struct stat {
     pub st_blksize: blksize_t,
     pub st_blocks: blkcnt_t,
 
-    pub st_atim: time_t,
-    pub st_mtim: time_t,
-    pub st_ctim: time_t,
+    pub st_atim: timespec,
+    pub st_mtim: timespec,
+    pub st_ctim: timespec,
 
-    // Compared to glibc, our struct is for some reason 48 bytes too small.
+    // Compared to glibc, our struct is for some reason 24 bytes too small.
     // Accessing atime works, so clearly the struct isn't incorrect...
     // This works.
-    pub _pad: [c_char; 48]
+    pub _pad: [c_char; 24]
 }
 
 pub const AF_INET: c_int = 2;
diff --git a/src/sys_stat/cbindgen.toml b/src/sys_stat/cbindgen.toml
index 538e2527820482e81cde48526cdd0ddc18f55a15..073794146a83d87d33b8f058d64053010ca32c6f 100644
--- a/src/sys_stat/cbindgen.toml
+++ b/src/sys_stat/cbindgen.toml
@@ -1,4 +1,4 @@
-sys_includes = ["sys/types.h"]
+sys_includes = ["sys/types.h", "time.h"]
 include_guard = "_SYS_STAT_H"
 trailer = "#include <bits/sys/stat.h>"
 language = "C"
diff --git a/src/sys_stat/src/lib.rs b/src/sys_stat/src/lib.rs
index 7806e85c4ba61230c34219413b6fc5f4a4fe300f..e894e0c718c2f78b0ffbccdf4992bffc49996b52 100644
--- a/src/sys_stat/src/lib.rs
+++ b/src/sys_stat/src/lib.rs
@@ -45,14 +45,14 @@ pub struct stat {
     pub st_blksize: blksize_t,
     pub st_blocks: blkcnt_t,
 
-    pub st_atim: time_t,
-    pub st_mtim: time_t,
-    pub st_ctim: time_t,
+    pub st_atim: timespec,
+    pub st_mtim: timespec,
+    pub st_ctim: timespec,
 
-    // Compared to glibc, our struct is for some reason 48 bytes too small.
+    // Compared to glibc, our struct is for some reason 24 bytes too small.
     // Accessing atime works, so clearly the struct isn't incorrect...
     // This works.
-    pub _pad: [c_char; 48]
+    pub _pad: [c_char; 24]
 }
 
 #[no_mangle]
@@ -75,6 +75,11 @@ pub extern "C" fn __fxstat(_ver: c_int, fildes: c_int, buf: *mut platform::types
     fstat(fildes, buf)
 }
 
+#[no_mangle]
+pub extern "C" fn futimens(fd: c_int, times: *const timespec) -> c_int {
+    platform::futimens(fd, times)
+}
+
 #[no_mangle]
 pub extern "C" fn lstat(path: *const c_char, buf: *mut platform::types::stat) -> c_int {
     platform::lstat(path, buf)
diff --git a/src/time/cbindgen.toml b/src/time/cbindgen.toml
index b0f4a5f349f2d91a46975ab32c55c34ed45be6cf..6186533acd472c57ef62037c528777fd639be8ef 100644
--- a/src/time/cbindgen.toml
+++ b/src/time/cbindgen.toml
@@ -1,4 +1,4 @@
-sys_includes = ["sys/types.h", "bits/timespec.h", "stdint.h", "stddef.h"]
+sys_includes = ["sys/types.h", "stdint.h", "stddef.h"]
 include_guard = "_TIME_H"
 language = "C"
 
diff --git a/src/time/src/lib.rs b/src/time/src/lib.rs
index 065cf792f54710aedf9fb1f3147083129b4186ba..6ed95d8314a72adb4316039c294f4cc42624da96 100644
--- a/src/time/src/lib.rs
+++ b/src/time/src/lib.rs
@@ -18,13 +18,11 @@ use errno::EIO;
 use helpers::*;
 use platform::types::*;
 
-/*
- *#[repr(C)]
- *pub struct timespec {
- *    pub tv_sec: time_t,
- *    pub tv_nsec: c_long,
- *}
- */
+#[repr(C)]
+pub struct timespec {
+    pub tv_sec: time_t,
+    pub tv_nsec: c_long,
+}
 
 #[repr(C)]
 pub struct tm {
@@ -124,7 +122,7 @@ pub extern "C" fn clock_getres(clock_id: clockid_t, res: *mut timespec) -> c_int
 
 #[no_mangle]
 pub extern "C" fn clock_gettime(clock_id: clockid_t, tp: *mut timespec) -> c_int {
-    platform::clock_gettime(clock_id, tp)
+    platform::clock_gettime(clock_id, tp as *mut platform::types::timespec)
 }
 
 // #[no_mangle]
@@ -331,7 +329,7 @@ pub unsafe extern "C" fn mktime(t: *const tm) -> time_t {
 
 #[no_mangle]
 pub extern "C" fn nanosleep(rqtp: *const timespec, rmtp: *mut timespec) -> c_int {
-    platform::nanosleep(rqtp, rmtp)
+    platform::nanosleep(rqtp as *const platform::types::timespec, rmtp as *mut platform::types::timespec)
 }
 
 #[no_mangle]
@@ -357,7 +355,7 @@ pub extern "C" fn strptime(buf: *const c_char, format: *const c_char, tm: *mut t
 
 #[no_mangle]
 pub extern "C" fn time(tloc: *mut time_t) -> time_t {
-    let mut ts: timespec = Default::default();
+    let mut ts: platform::types::timespec = Default::default();
     platform::clock_gettime(CLOCK_REALTIME, &mut ts);
     unsafe {
         if !tloc.is_null() {
diff --git a/tests/time/gettimeofday b/tests/time/gettimeofday
deleted file mode 100755
index f5d629fb6b43bed07266b76651f34cc597fa4696..0000000000000000000000000000000000000000
Binary files a/tests/time/gettimeofday and /dev/null differ