diff --git a/cc3200/application.mk b/cc3200/application.mk
index f3ed40a72bda18d85303096498c8ff7bfe0b17a9..29be228bd1f6860e550812a9bdc2de81d4a72288 100644
--- a/cc3200/application.mk
+++ b/cc3200/application.mk
@@ -21,6 +21,7 @@ APP_INC += -I$(BUILD)/genhdr
 APP_INC += -I../lib/fatfs
 APP_INC += -I../lib/mp-readline
 APP_INC += -I../lib/netutils
+APP_INC += -I../lib/timeutils
 APP_INC += -I../stmhal
 
 APP_CPPDEFINES = -Dgcc -DTARGET_IS_CC3200 -DSL_FULL -DUSE_FREERTOS
@@ -144,6 +145,7 @@ APP_LIB_SRC_C = $(addprefix lib/,\
 	libc/string0.c \
 	mp-readline/readline.c \
 	netutils/netutils.c \
+	timeutils/timeutils.c \
 	)
 	
 APP_STM_SRC_C = $(addprefix stmhal/,\
diff --git a/cc3200/fatfs/src/diskio.c b/cc3200/fatfs/src/diskio.c
index 8a6b5704d76d26052447f832c89754a8a78df948..55e7e1916e40bea7a9a7cf9710061b838072f12c 100644
--- a/cc3200/fatfs/src/diskio.c
+++ b/cc3200/fatfs/src/diskio.c
@@ -15,12 +15,12 @@
 #if MICROPY_HW_HAS_SDCARD
 #include "sd_diskio.h"		    /* SDCARD disk IO API */
 #endif
-#include "modutime.h"
 #include "inc/hw_types.h"
 #include "inc/hw_ints.h"
 #include "inc/hw_memmap.h"
 #include "rom_map.h"
 #include "prcm.h"
+#include "timeutils.h"
 
 /* Definitions of physical drive number for each drive */
 #define SFLASH		0	/* Map SFLASH drive to drive number 0 */
@@ -192,13 +192,13 @@ DWORD get_fattime (
     void
 )
 {
-    mod_struct_time tm;
+    timeutils_struct_time_t tm;
     uint32_t seconds;
     uint16_t mseconds;
 
     // Get the time from the on-chip RTC and convert it to struct_time
     MAP_PRCMRTCGet(&seconds, &mseconds);
-    mod_time_seconds_since_2000_to_struct_time(seconds, &tm);
+    timeutils_seconds_since_2000_to_struct_time(seconds, &tm);
 
     return ((tm.tm_year - 1980) << 25) | ((tm.tm_mon) << 21)  |
             ((tm.tm_mday) << 16)       | ((tm.tm_hour) << 11) |
diff --git a/cc3200/ftp/ftp.c b/cc3200/ftp/ftp.c
index ebc9dcd9a006e6bf600757fe24f71a79a12b61de..3dc0923ce27591ad293f967fe3c67ea371713ad0 100644
--- a/cc3200/ftp/ftp.c
+++ b/cc3200/ftp/ftp.c
@@ -40,7 +40,6 @@
 #include "ftp.h"
 #include "simplelink.h"
 #include "modwlan.h"
-#include "modutime.h"
 #include "debug.h"
 #include "serverstask.h"
 #include "ff.h"
@@ -49,6 +48,7 @@
 #include "diskio.h"
 #include "sd_diskio.h"
 #include "updater.h"
+#include "timeutils.h"
 
 
 /******************************************************************************
@@ -884,7 +884,7 @@ static int ftp_print_eplf_item (char *dest, uint32_t destsize, FILINFO *fno) {
     uint16_t mseconds;
     uint mindex = (((fno->fdate >> 5) & 0x0f) > 0) ? (((fno->fdate >> 5) & 0x0f) - 1) : 0;
     uint day = ((fno->fdate & 0x1f) > 0) ? (fno->fdate & 0x1f) : 1;
-    uint fseconds = mod_time_seconds_since_2000(1980 + ((fno->fdate >> 9) & 0x7f),
+    uint fseconds = timeutils_seconds_since_2000(1980 + ((fno->fdate >> 9) & 0x7f),
                                                         (fno->fdate >> 5) & 0x0f,
                                                         fno->fdate & 0x1f,
                                                         (fno->ftime >> 11) & 0x1f,
@@ -912,12 +912,12 @@ static int ftp_print_eplf_item (char *dest, uint32_t destsize, FILINFO *fno) {
 }
 
 static int ftp_print_eplf_drive (char *dest, uint32_t destsize, char *name) {
-    mod_struct_time tm;
+    timeutils_struct_time_t tm;
     uint32_t tseconds;
     uint16_t mseconds;
     char *type = "d";
 
-    mod_time_seconds_since_2000_to_struct_time((FTP_UNIX_TIME_20150101 - FTP_UNIX_TIME_20000101), &tm);
+    timeutils_seconds_since_2000_to_struct_time((FTP_UNIX_TIME_20150101 - FTP_UNIX_TIME_20000101), &tm);
 
     MAP_PRCMRTCGet(&tseconds, &mseconds);
     if (FTP_UNIX_SECONDS_180_DAYS < tseconds - (FTP_UNIX_TIME_20150101 - FTP_UNIX_TIME_20000101)) {
diff --git a/cc3200/mods/moduos.c b/cc3200/mods/moduos.c
index 72f848cfef93534ef25298ee7cc2e5bdd6762368..71b70be29671f415b93ccd1cac4013aa2e246351 100644
--- a/cc3200/mods/moduos.c
+++ b/cc3200/mods/moduos.c
@@ -38,11 +38,11 @@
 #include "diskio.h"
 #include "sflash_diskio.h"
 #include "file.h"
-#include "modutime.h"
 #include "random.h"
 #include "sd_diskio.h"
 #include "mpexception.h"
 #include "version.h"
+#include "timeutils.h"
 
 /// \module os - basic "operating system" services
 ///
@@ -285,7 +285,7 @@ STATIC mp_obj_t os_stat(mp_obj_t path_in) {
     } else {
         mode |= 0x8000; // stat.S_IFREG
     }
-    mp_int_t seconds = mod_time_seconds_since_2000(
+    mp_int_t seconds = timeutils_seconds_since_2000(
         1980 + ((fno.fdate >> 9) & 0x7f),
         (fno.fdate >> 5) & 0x0f,
         fno.fdate & 0x1f,
diff --git a/cc3200/mods/modutime.c b/cc3200/mods/modutime.c
index 07896512d854b300c7efe9696935e32100c0a98f..dc4fcf152cc7807816a86c169e55b248a707dced 100644
--- a/cc3200/mods/modutime.c
+++ b/cc3200/mods/modutime.c
@@ -32,7 +32,7 @@
 #include MICROPY_HAL_H
 #include "py/nlr.h"
 #include "py/obj.h"
-#include "modutime.h"
+#include "timeutils.h"
 #include "inc/hw_types.h"
 #include "inc/hw_ints.h"
 #include "inc/hw_memmap.h"
@@ -41,126 +41,11 @@
 #include "pybrtc.h"
 #include "mpexception.h"
 
-
-// LEAPOCH corresponds to 2000-03-01, which is a mod-400 year, immediately
-// after Feb 29. We calculate seconds as a signed integer relative to that.
-//
-// Our timebase is relative to 2000-01-01.
-
-#define LEAPOCH ((31 + 29) * 86400)
-
-#define DAYS_PER_400Y (365*400 + 97)
-#define DAYS_PER_100Y (365*100 + 24)
-#define DAYS_PER_4Y   (365*4   + 1)
-
-
 /// \module time - time related functions
 ///
 /// The `time` module provides functions for getting the current time and date,
 /// and for sleeping.
 
-STATIC const uint16_t days_since_jan1[]= { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
-
-STATIC bool is_leap_year(mp_uint_t year) {
-    return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
-}
-
-// Month is one based
-STATIC mp_uint_t mod_time_days_in_month(mp_uint_t year, mp_uint_t month) {
-    mp_uint_t mdays = days_since_jan1[month] - days_since_jan1[month - 1];
-    if (month == 2 && is_leap_year(year)) {
-        mdays++;
-    }
-    return mdays;
-}
-
-// compute the day of the year, between 1 and 366
-// month should be between 1 and 12, date should start at 1
-STATIC mp_uint_t mod_time_year_day(mp_uint_t year, mp_uint_t month, mp_uint_t date) {
-    mp_uint_t yday = days_since_jan1[month - 1] + date;
-    if (month >= 3 && is_leap_year(year)) {
-        yday += 1;
-    }
-    return yday;
-}
-
-// returns the number of seconds, as an integer, since 2000-01-01
-mp_uint_t mod_time_seconds_since_2000(mp_uint_t year, mp_uint_t month, mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second) {
-    return
-        second
-        + minute * 60
-        + hour * 3600
-        + (mod_time_year_day(year, month, date) - 1
-            + ((year - 2000 + 3) / 4) // add a day each 4 years starting with 2001
-            - ((year - 2000 + 99) / 100) // subtract a day each 100 years starting with 2001
-            + ((year - 2000 + 399) / 400) // add a day each 400 years starting with 2001
-            ) * 86400
-        + (year - 2000) * 31536000;
-}
-
-void mod_time_seconds_since_2000_to_struct_time(mp_uint_t t, mod_struct_time *tm) {
-    // The following algorithm was adapted from musl's __secs_to_tm and adapted
-    // for differences in Micro Python's timebase.
-
-    mp_int_t seconds = t - LEAPOCH;
-
-    mp_int_t days = seconds / 86400;
-    seconds %= 86400;
-    tm->tm_hour = seconds / 3600;
-    tm->tm_min = seconds / 60 % 60;
-    tm->tm_sec = seconds % 60;
-
-    mp_int_t wday = (days + 2) % 7;   // Mar 1, 2000 was a Wednesday (2)
-    if (wday < 0) {
-        wday += 7;
-    }
-    tm->tm_wday = wday;
-
-    mp_int_t qc_cycles = days / DAYS_PER_400Y;
-    days %= DAYS_PER_400Y;
-    if (days < 0) {
-        days += DAYS_PER_400Y;
-        qc_cycles--;
-    }
-    mp_int_t c_cycles = days / DAYS_PER_100Y;
-    if (c_cycles == 4) {
-        c_cycles--;
-    }
-    days -= (c_cycles * DAYS_PER_100Y);
-
-    mp_int_t q_cycles = days / DAYS_PER_4Y;
-    if (q_cycles == 25) {
-        q_cycles--;
-    }
-    days -= q_cycles * DAYS_PER_4Y;
-
-    mp_int_t years = days / 365;
-    if (years == 4) {
-        years--;
-    }
-    days -= (years * 365);
-
-    tm->tm_year = 2000 + years + 4 * q_cycles + 100 * c_cycles + 400 * qc_cycles;
-
-    // Note: days_in_month[0] corresponds to March
-    STATIC const int8_t days_in_month[] = {31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29};
-
-    mp_int_t month;
-    for (month = 0; days_in_month[month] <= days; month++) {
-        days -= days_in_month[month];
-    }
-
-    tm->tm_mon = month + 2;
-    if (tm->tm_mon >= 12) {
-        tm->tm_mon -= 12;
-        tm->tm_year++;
-    }
-    tm->tm_mday = days + 1; // Make one based
-    tm->tm_mon++;   // Make one based
-
-    tm->tm_yday = mod_time_year_day(tm->tm_year, tm->tm_mon, tm->tm_mday);
-}
-
 /// \function localtime([secs])
 /// Convert a time expressed in seconds since Jan 1, 2000 into an 8-tuple which
 /// contains: (year, month, mday, hour, minute, second, weekday, yearday)
@@ -175,14 +60,14 @@ void mod_time_seconds_since_2000_to_struct_time(mp_uint_t t, mod_struct_time *tm
 /// yearday is 1-366
 STATIC mp_obj_t time_localtime(mp_uint_t n_args, const mp_obj_t *args) {
     if (n_args == 0 || args[0] == mp_const_none) {
-        mod_struct_time tm;
+        timeutils_struct_time_t tm;
         uint32_t seconds;
         uint16_t mseconds;
 
         // get the seconds and the milliseconds from the RTC
         MAP_PRCMRTCGet(&seconds, &mseconds);
         mseconds = RTC_CYCLES_U16MS(mseconds);
-        mod_time_seconds_since_2000_to_struct_time(seconds, &tm);
+        timeutils_seconds_since_2000_to_struct_time(seconds, &tm);
 
         mp_obj_t tuple[8] = {
                 mp_obj_new_int(tm.tm_year),
@@ -197,8 +82,8 @@ STATIC mp_obj_t time_localtime(mp_uint_t n_args, const mp_obj_t *args) {
         return mp_obj_new_tuple(8, tuple);
     } else {
         mp_int_t seconds = mp_obj_get_int(args[0]);
-        mod_struct_time tm;
-        mod_time_seconds_since_2000_to_struct_time(seconds, &tm);
+        timeutils_struct_time_t tm;
+        timeutils_seconds_since_2000_to_struct_time(seconds, &tm);
         mp_obj_t tuple[8] = {
             tuple[0] = mp_obj_new_int(tm.tm_year),
             tuple[1] = mp_obj_new_int(tm.tm_mon),
@@ -231,64 +116,10 @@ STATIC mp_obj_t time_mktime(mp_obj_t tuple) {
         nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, mpexception_num_type_invalid_arguments));
     }
 
-    mp_int_t year    = mp_obj_get_int(elem[0]);
-    mp_int_t month   = mp_obj_get_int(elem[1]);
-    mp_int_t mday    = mp_obj_get_int(elem[2]);
-    mp_int_t hours   = mp_obj_get_int(elem[3]);
-    mp_int_t minutes = mp_obj_get_int(elem[4]);
-    mp_int_t seconds = mp_obj_get_int(elem[5]);
+    return mp_obj_new_int_from_uint(timeutils_mktime(mp_obj_get_int(elem[0]),
+            mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]), mp_obj_get_int(elem[3]),
+            mp_obj_get_int(elem[4]), mp_obj_get_int(elem[5])));
 
-    // Normalize the tuple. This allows things like:
-    //
-    // tm_tomorrow = list(time.localtime())
-    // tm_tomorrow[2] += 1 # Adds 1 to mday
-    // tomorrow = time.mktime(tm_tommorrow)
-    //
-    // And not have to worry about all the weird overflows.
-    //
-    // You can subtract dates/times this way as well.
-
-    minutes += seconds / 60;
-    if ((seconds = seconds % 60) < 0) {
-        seconds += 60;
-        minutes--;
-    }
-
-    hours += minutes / 60;
-    if ((minutes = minutes % 60) < 0) {
-        minutes += 60;
-        hours--;
-    }
-
-    mday += hours / 24;
-    if ((hours = hours % 24) < 0) {
-        hours += 24;
-        mday--;
-    }
-
-    month--; // make month zero based
-    year += month / 12;
-    if ((month = month % 12) < 0) {
-        month += 12;
-        year--;
-    }
-    month++; // back to one based
-
-    while (mday < 1) {
-        if (--month == 0) {
-            month = 12;
-            year--;
-        }
-        mday += mod_time_days_in_month(year, month);
-    }
-    while (mday > mod_time_days_in_month(year, month)) {
-        mday -= mod_time_days_in_month(year, month);
-        if (++month == 13) {
-            month = 1;
-            year++;
-        }
-    }
-    return mp_obj_new_int_from_uint(mod_time_seconds_since_2000(year, month, mday, hours, minutes, seconds));
 }
 MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime);
 
diff --git a/cc3200/mods/pybrtc.c b/cc3200/mods/pybrtc.c
index 95b676d4a3316c106c9d00c0e734bae551b8cdf6..d57e11167c5a1e3592d22b0ea5da87dea4ebd832 100644
--- a/cc3200/mods/pybrtc.c
+++ b/cc3200/mods/pybrtc.c
@@ -31,7 +31,6 @@
 #include MICROPY_HAL_H
 #include "py/obj.h"
 #include "py/runtime.h"
-#include "modutime.h"
 #include "inc/hw_types.h"
 #include "inc/hw_ints.h"
 #include "inc/hw_memmap.h"
@@ -40,6 +39,7 @@
 #include "pybrtc.h"
 #include "pybsleep.h"
 #include "mpcallback.h"
+#include "timeutils.h"
 
 /// \moduleref pyb
 /// \class RTC - real time clock
@@ -82,7 +82,7 @@ void pybrtc_init(void) {
         // fresh reset; configure the RTC Calendar
         // set the date to 1st Jan 2015
         // set the time to 00:00:00
-        uint32_t seconds = mod_time_seconds_since_2000(2015, 1, 1, 0, 0, 0);
+        uint32_t seconds = timeutils_seconds_since_2000(2015, 1, 1, 0, 0, 0);
 
         // Mark the RTC in use first
         MAP_PRCMRTCInUseSet();
@@ -137,7 +137,7 @@ STATIC void pyb_rtc_callback_disable (mp_obj_t self_in) {
 /// `weekday` is 0-6 for Monday through Sunday.
 ///
 mp_obj_t pyb_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) {
-    mod_struct_time tm;
+    timeutils_struct_time_t tm;
     uint32_t seconds;
     uint16_t mseconds;
 
@@ -145,7 +145,7 @@ mp_obj_t pyb_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) {
         // get the seconds and the milliseconds from the RTC
         MAP_PRCMRTCGet(&seconds, &mseconds);
         mseconds = RTC_CYCLES_U16MS(mseconds);
-        mod_time_seconds_since_2000_to_struct_time(seconds, &tm);
+        timeutils_seconds_since_2000_to_struct_time(seconds, &tm);
 
         mp_obj_t tuple[8] = {
             mp_obj_new_int(tm.tm_year),
@@ -172,7 +172,7 @@ mp_obj_t pyb_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) {
         tm.tm_sec = mp_obj_get_int(items[6]);
         mseconds = mp_obj_get_int(items[7]);
 
-        seconds = mod_time_seconds_since_2000(tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
+        seconds = timeutils_seconds_since_2000(tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
         mseconds = RTC_U16MS_CYCLES(mseconds);
         MAP_PRCMRTCSet(seconds, mseconds);
 
diff --git a/lib/timeutils/timeutils.c b/lib/timeutils/timeutils.c
new file mode 100644
index 0000000000000000000000000000000000000000..77e5f043f1515fc5d8d8158298168cc99138e452
--- /dev/null
+++ b/lib/timeutils/timeutils.c
@@ -0,0 +1,211 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013, 2014 Damien P. George
+ * Copyright (c) 2015 Daniel Campora
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+
+#include "timeutils.h"
+
+// LEAPOCH corresponds to 2000-03-01, which is a mod-400 year, immediately
+// after Feb 29. We calculate seconds as a signed integer relative to that.
+//
+// Our timebase is is relative to 2000-01-01.
+
+#define LEAPOCH ((31 + 29) * 86400)
+
+#define DAYS_PER_400Y (365*400 + 97)
+#define DAYS_PER_100Y (365*100 + 24)
+#define DAYS_PER_4Y   (365*4   + 1)
+
+STATIC const uint16_t days_since_jan1[]= { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
+
+bool timeutils_is_leap_year(mp_uint_t year) {
+    return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
+}
+
+// month is one based
+mp_uint_t timeutils_days_in_month(mp_uint_t year, mp_uint_t month) {
+    mp_uint_t mdays = days_since_jan1[month] - days_since_jan1[month - 1];
+    if (month == 2 && timeutils_is_leap_year(year)) {
+        mdays++;
+    }
+    return mdays;
+}
+
+// compute the day of the year, between 1 and 366
+// month should be between 1 and 12, date should start at 1
+mp_uint_t timeutils_year_day(mp_uint_t year, mp_uint_t month, mp_uint_t date) {
+    mp_uint_t yday = days_since_jan1[month - 1] + date;
+    if (month >= 3 && timeutils_is_leap_year(year)) {
+        yday += 1;
+    }
+    return yday;
+}
+
+void timeutils_seconds_since_2000_to_struct_time(mp_uint_t t, timeutils_struct_time_t *tm) {
+    // The following algorithm was adapted from musl's __secs_to_tm and adapted
+    // for differences in Micro Python's timebase.
+
+    mp_int_t seconds = t - LEAPOCH;
+
+    mp_int_t days = seconds / 86400;
+    seconds %= 86400;
+    tm->tm_hour = seconds / 3600;
+    tm->tm_min = seconds / 60 % 60;
+    tm->tm_sec = seconds % 60;
+
+    mp_int_t wday = (days + 2) % 7;   // Mar 1, 2000 was a Wednesday (2)
+    if (wday < 0) {
+        wday += 7;
+    }
+    tm->tm_wday = wday;
+
+    mp_int_t qc_cycles = days / DAYS_PER_400Y;
+    days %= DAYS_PER_400Y;
+    if (days < 0) {
+        days += DAYS_PER_400Y;
+        qc_cycles--;
+    }
+    mp_int_t c_cycles = days / DAYS_PER_100Y;
+    if (c_cycles == 4) {
+        c_cycles--;
+    }
+    days -= (c_cycles * DAYS_PER_100Y);
+
+    mp_int_t q_cycles = days / DAYS_PER_4Y;
+    if (q_cycles == 25) {
+        q_cycles--;
+    }
+    days -= q_cycles * DAYS_PER_4Y;
+
+    mp_int_t years = days / 365;
+    if (years == 4) {
+        years--;
+    }
+    days -= (years * 365);
+
+    /* We will compute tm_yday at the very end
+    mp_int_t leap = !years && (q_cycles || !c_cycles);
+
+    tm->tm_yday = days + 31 + 28 + leap;
+    if (tm->tm_yday >= 365 + leap) {
+        tm->tm_yday -= 365 + leap;
+    }
+
+    tm->tm_yday++;  // Make one based
+    */
+
+    tm->tm_year = 2000 + years + 4 * q_cycles + 100 * c_cycles + 400 * qc_cycles;
+
+    // Note: days_in_month[0] corresponds to March
+    STATIC const int8_t days_in_month[] = {31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29};
+
+    mp_int_t month;
+    for (month = 0; days_in_month[month] <= days; month++) {
+        days -= days_in_month[month];
+    }
+
+    tm->tm_mon = month + 2;
+    if (tm->tm_mon >= 12) {
+        tm->tm_mon -= 12;
+        tm->tm_year++;
+    }
+    tm->tm_mday = days + 1; // Make one based
+    tm->tm_mon++;   // Make one based
+
+    tm->tm_yday = timeutils_year_day(tm->tm_year, tm->tm_mon, tm->tm_mday);
+}
+
+// returns the number of seconds, as an integer, since 2000-01-01
+mp_uint_t timeutils_seconds_since_2000(mp_uint_t year, mp_uint_t month,
+    mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second) {
+    return
+        second
+        + minute * 60
+        + hour * 3600
+        + (timeutils_year_day(year, month, date) - 1
+            + ((year - 2000 + 3) / 4) // add a day each 4 years starting with 2001
+            - ((year - 2000 + 99) / 100) // subtract a day each 100 years starting with 2001
+            + ((year - 2000 + 399) / 400) // add a day each 400 years starting with 2001
+            ) * 86400
+        + (year - 2000) * 31536000;
+}
+
+mp_uint_t timeutils_mktime(mp_uint_t year, mp_uint_t month, mp_uint_t mday,
+    mp_uint_t hours, mp_uint_t minutes, mp_uint_t seconds) {
+
+    // Normalize the tuple. This allows things like:
+    //
+    // tm_tomorrow = list(time.localtime())
+    // tm_tomorrow[2] += 1 # Adds 1 to mday
+    // tomorrow = time.mktime(tm_tommorrow)
+    //
+    // And not have to worry about all the weird overflows.
+    //
+    // You can subtract dates/times this way as well.
+
+    minutes += seconds / 60;
+    if ((seconds = seconds % 60) < 0) {
+        seconds += 60;
+        minutes--;
+    }
+
+    hours += minutes / 60;
+    if ((minutes = minutes % 60) < 0) {
+        minutes += 60;
+        hours--;
+    }
+
+    mday += hours / 24;
+    if ((hours = hours % 24) < 0) {
+        hours += 24;
+        mday--;
+    }
+
+    month--; // make month zero based
+    year += month / 12;
+    if ((month = month % 12) < 0) {
+        month += 12;
+        year--;
+    }
+    month++; // back to one based
+
+    while (mday < 1) {
+        if (--month == 0) {
+            month = 12;
+            year--;
+        }
+        mday += timeutils_days_in_month(year, month);
+    }
+    while (mday > timeutils_days_in_month(year, month)) {
+        mday -= timeutils_days_in_month(year, month);
+        if (++month == 13) {
+            month = 1;
+            year++;
+        }
+    }
+    return timeutils_seconds_since_2000(year, month, mday, hours, minutes, seconds);
+}
diff --git a/cc3200/mods/modutime.h b/lib/timeutils/timeutils.h
similarity index 67%
rename from cc3200/mods/modutime.h
rename to lib/timeutils/timeutils.h
index 17481a06445e127c78d459ad4a332d5840d05ae0..d6e3536ad7eabedd1071e1ed3b161b0d230e2581 100644
--- a/cc3200/mods/modutime.h
+++ b/lib/timeutils/timeutils.h
@@ -25,10 +25,10 @@
  * THE SOFTWARE.
  */
 
-#ifndef MODUTIME_H_
-#define MODUTIME_H_
+#ifndef __MICROPY_INCLUDED_LIB_TIMEUTILS_H__
+#define __MICROPY_INCLUDED_LIB_TIMEUTILS_H__
 
-typedef struct {
+typedef struct _timeutils_struct_time_t {
     uint16_t    tm_year;    // i.e. 2014
     uint8_t     tm_mon;     // 1..12
     uint8_t     tm_mday;    // 1..31
@@ -37,12 +37,19 @@ typedef struct {
     uint8_t     tm_sec;     // 0..59
     uint8_t     tm_wday;    // 0..6  0 = Monday
     uint16_t    tm_yday;    // 1..366
-} mod_struct_time;
+} timeutils_struct_time_t;
 
+bool timeutils_is_leap_year(mp_uint_t year);
+mp_uint_t timeutils_days_in_month(mp_uint_t year, mp_uint_t month);
+mp_uint_t timeutils_year_day(mp_uint_t year, mp_uint_t month, mp_uint_t date);
 
-extern mp_uint_t mod_time_seconds_since_2000(mp_uint_t year, mp_uint_t month, mp_uint_t date,
-                                             mp_uint_t hour, mp_uint_t minute, mp_uint_t second);
+void timeutils_seconds_since_2000_to_struct_time(mp_uint_t t,
+    timeutils_struct_time_t *tm);
 
-extern void mod_time_seconds_since_2000_to_struct_time(mp_uint_t t, mod_struct_time *tm);
+mp_uint_t timeutils_seconds_since_2000(mp_uint_t year, mp_uint_t month,
+    mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second);
 
-#endif // MODUTIME_H_
+mp_uint_t timeutils_mktime(mp_uint_t year, mp_uint_t month, mp_uint_t mday,
+    mp_uint_t hours, mp_uint_t minutes, mp_uint_t seconds);
+
+#endif // __MICROPY_INCLUDED_LIB_TIMEUTILS_H__
diff --git a/stmhal/Makefile b/stmhal/Makefile
index 60f05669b27124f0927458f05a6a89af764da9f6..5751ad40596572ce1a020195824acf5e1e81f783 100644
--- a/stmhal/Makefile
+++ b/stmhal/Makefile
@@ -42,6 +42,7 @@ INC += -I$(USBDEV_DIR)/core/inc -I$(USBDEV_DIR)/class/inc
 #INC += -I$(USBHOST_DIR)
 INC += -I../lib/mp-readline
 INC += -I../lib/netutils
+INC += -I../lib/timeutils
 
 CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -mabi=aapcs-linux -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -fsingle-precision-constant -Wdouble-promotion
 CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -ansi -std=gnu99 -nostdlib $(CFLAGS_MOD) $(CFLAGS_CORTEX_M4) $(COPT)
@@ -94,6 +95,7 @@ SRC_LIB = $(addprefix lib/,\
 	fatfs/option/ccsbcs.c \
 	mp-readline/readline.c \
 	netutils/netutils.c \
+	timeutils/timeutils.c \
 	)
 
 SRC_C = \
diff --git a/stmhal/moduos.c b/stmhal/moduos.c
index 24f2e0f1f2f14546f9da1c973543126fff18c008..55404c77bd92deef4fb83ee61d9e9156ddd5873d 100644
--- a/stmhal/moduos.c
+++ b/stmhal/moduos.c
@@ -34,6 +34,7 @@
 #include "genhdr/mpversion.h"
 #include "lib/fatfs/ff.h"
 #include "lib/fatfs/diskio.h"
+#include "timeutils.h"
 #include "rng.h"
 #include "file.h"
 #include "sdcard.h"
@@ -322,7 +323,7 @@ STATIC mp_obj_t os_stat(mp_obj_t path_in) {
     } else {
         mode |= 0x8000; // stat.S_IFREG
     }
-    mp_int_t seconds = mod_time_seconds_since_2000(
+    mp_int_t seconds = timeutils_seconds_since_2000(
         1980 + ((fno.fdate >> 9) & 0x7f),
         (fno.fdate >> 5) & 0x0f,
         fno.fdate & 0x1f,
diff --git a/stmhal/modutime.c b/stmhal/modutime.c
index b918b1e9a794dc0534624e0b2f1f14552b18a667..75605a37c3cbd0c79d12411054cb6d8385917a91 100644
--- a/stmhal/modutime.c
+++ b/stmhal/modutime.c
@@ -30,6 +30,7 @@
 
 #include "py/nlr.h"
 #include "py/obj.h"
+#include "timeutils.h"
 #include "portmodules.h"
 #include "rtc.h"
 
@@ -38,141 +39,6 @@
 /// The `time` module provides functions for getting the current time and date,
 /// and for sleeping.
 
-STATIC const uint16_t days_since_jan1[]= { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
-
-STATIC bool is_leap_year(mp_uint_t year) {
-    return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
-}
-
-// Month is one based
-STATIC mp_uint_t mod_time_days_in_month(mp_uint_t year, mp_uint_t month) {
-    mp_uint_t mdays = days_since_jan1[month] - days_since_jan1[month - 1];
-    if (month == 2 && is_leap_year(year)) {
-        mdays++;
-    }
-    return mdays;
-}
-
-// compute the day of the year, between 1 and 366
-// month should be between 1 and 12, date should start at 1
-STATIC mp_uint_t mod_time_year_day(mp_uint_t year, mp_uint_t month, mp_uint_t date) {
-    mp_uint_t yday = days_since_jan1[month - 1] + date;
-    if (month >= 3 && is_leap_year(year)) {
-        yday += 1;
-    }
-    return yday;
-}
-
-// returns the number of seconds, as an integer, since 2000-01-01
-mp_uint_t mod_time_seconds_since_2000(mp_uint_t year, mp_uint_t month, mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second) {
-    return
-        second
-        + minute * 60
-        + hour * 3600
-        + (mod_time_year_day(year, month, date) - 1
-            + ((year - 2000 + 3) / 4) // add a day each 4 years starting with 2001
-            - ((year - 2000 + 99) / 100) // subtract a day each 100 years starting with 2001
-            + ((year - 2000 + 399) / 400) // add a day each 400 years starting with 2001
-            ) * 86400
-        + (year - 2000) * 31536000;
-}
-
-// LEAPOCH corresponds to 2000-03-01, which is a mod-400 year, immediately
-// after Feb 29. We calculate seconds as a signed integer relative to that.
-//
-// Our timebase is is relative to 2000-01-01.
-
-#define LEAPOCH ((31 + 29) * 86400)
-
-#define DAYS_PER_400Y (365*400 + 97)
-#define DAYS_PER_100Y (365*100 + 24)
-#define DAYS_PER_4Y   (365*4   + 1)
-
-typedef struct {
-    uint16_t    tm_year;    // i.e. 2014
-    uint8_t     tm_mon;     // 1..12
-    uint8_t     tm_mday;    // 1..31
-    uint8_t     tm_hour;    // 0..23
-    uint8_t     tm_min;     // 0..59
-    uint8_t     tm_sec;     // 0..59
-    uint8_t     tm_wday;    // 0..6  0 = Monday
-    uint16_t    tm_yday;    // 1..366
-} mod_struct_time;
-
-STATIC void mod_time_seconds_since_2000_to_struct_time(mp_uint_t t, mod_struct_time *tm) {
-    // The following algorithm was adapted from musl's __secs_to_tm and adapted
-    // for differences in Micro Python's timebase.
-
-    mp_int_t seconds = t - LEAPOCH;
-
-    mp_int_t days = seconds / 86400;
-    seconds %= 86400;
-    tm->tm_hour = seconds / 3600;
-    tm->tm_min = seconds / 60 % 60;
-    tm->tm_sec = seconds % 60;
-
-    mp_int_t wday = (days + 2) % 7;   // Mar 1, 2000 was a Wednesday (2)
-    if (wday < 0) {
-        wday += 7;
-    }
-    tm->tm_wday = wday;
-
-    mp_int_t qc_cycles = days / DAYS_PER_400Y;
-    days %= DAYS_PER_400Y;
-    if (days < 0) {
-        days += DAYS_PER_400Y;
-        qc_cycles--;
-    }
-    mp_int_t c_cycles = days / DAYS_PER_100Y;
-    if (c_cycles == 4) {
-        c_cycles--;
-    }
-    days -= (c_cycles * DAYS_PER_100Y);
-
-    mp_int_t q_cycles = days / DAYS_PER_4Y;
-    if (q_cycles == 25) {
-        q_cycles--;
-    }
-    days -= q_cycles * DAYS_PER_4Y;
-
-    mp_int_t years = days / 365;
-    if (years == 4) {
-        years--;
-    }
-    days -= (years * 365);
-
-    /* We will compute tm_yday at the very end
-    mp_int_t leap = !years && (q_cycles || !c_cycles);
-
-    tm->tm_yday = days + 31 + 28 + leap;
-    if (tm->tm_yday >= 365 + leap) {
-        tm->tm_yday -= 365 + leap;
-    }
-
-    tm->tm_yday++;  // Make one based
-    */
-
-    tm->tm_year = 2000 + years + 4 * q_cycles + 100 * c_cycles + 400 * qc_cycles;
-
-    // Note: days_in_month[0] corresponds to March
-    STATIC const int8_t days_in_month[] = {31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29};
-
-    mp_int_t month;
-    for (month = 0; days_in_month[month] <= days; month++) {
-        days -= days_in_month[month];
-    }
-
-    tm->tm_mon = month + 2;
-    if (tm->tm_mon >= 12) {
-        tm->tm_mon -= 12;
-        tm->tm_year++;
-    }
-    tm->tm_mday = days + 1; // Make one based
-    tm->tm_mon++;   // Make one based
-
-    tm->tm_yday = mod_time_year_day(tm->tm_year, tm->tm_mon, tm->tm_mday);
-}
-
 /// \function localtime([secs])
 /// Convert a time expressed in seconds since Jan 1, 2000 into an 8-tuple which
 /// contains: (year, month, mday, hour, minute, second, weekday, yearday)
@@ -201,13 +67,13 @@ STATIC mp_obj_t time_localtime(mp_uint_t n_args, const mp_obj_t *args) {
             mp_obj_new_int(time.Minutes),
             mp_obj_new_int(time.Seconds),
             mp_obj_new_int(date.WeekDay - 1),
-            mp_obj_new_int(mod_time_year_day(2000 + date.Year, date.Month, date.Date)),
+            mp_obj_new_int(timeutils_year_day(2000 + date.Year, date.Month, date.Date)),
         };
         return mp_obj_new_tuple(8, tuple);
     } else {
         mp_int_t seconds = mp_obj_get_int(args[0]);
-        mod_struct_time tm;
-        mod_time_seconds_since_2000_to_struct_time(seconds, &tm);
+        timeutils_struct_time_t tm;
+        timeutils_seconds_since_2000_to_struct_time(seconds, &tm);
         mp_obj_t tuple[8] = {
             tuple[0] = mp_obj_new_int(tm.tm_year),
             tuple[1] = mp_obj_new_int(tm.tm_mon),
@@ -240,64 +106,9 @@ STATIC mp_obj_t time_mktime(mp_obj_t tuple) {
         nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "mktime needs a tuple of length 8 or 9 (%d given)", len));
     }
 
-    mp_int_t year    = mp_obj_get_int(elem[0]);
-    mp_int_t month   = mp_obj_get_int(elem[1]);
-    mp_int_t mday    = mp_obj_get_int(elem[2]);
-    mp_int_t hours   = mp_obj_get_int(elem[3]);
-    mp_int_t minutes = mp_obj_get_int(elem[4]);
-    mp_int_t seconds = mp_obj_get_int(elem[5]);
-
-    // Normalise the tuple. This allows things like:
-    //
-    // tm_tomorrow = list(time.localtime())
-    // tm_tomorrow[2] += 1 # Adds 1 to mday
-    // tomorrow = time.mktime(tm_tommorrow)
-    //
-    // And not have to worry about all the weird overflows.
-    //
-    // You can subtract dates/times this way as well.
-
-    minutes += seconds / 60;
-    if ((seconds = seconds % 60) < 0) {
-        seconds += 60;
-        minutes--;
-    }
-
-    hours += minutes / 60;
-    if ((minutes = minutes % 60) < 0) {
-        minutes += 60;
-        hours--;
-    }
-
-    mday += hours / 24;
-    if ((hours = hours % 24) < 0) {
-        hours += 24;
-        mday--;
-    }
-
-    month--; // make month zero based
-    year += month / 12;
-    if ((month = month % 12) < 0) {
-        month += 12;
-        year--;
-    }
-    month++; // back to one based
-
-    while (mday < 1) {
-        if (--month == 0) {
-            month = 12;
-            year--;
-        }
-        mday += mod_time_days_in_month(year, month);
-    }
-    while (mday > mod_time_days_in_month(year, month)) {
-        mday -= mod_time_days_in_month(year, month);
-        if (++month == 13) {
-            month = 1;
-            year++;
-        }
-    }
-    return mp_obj_new_int_from_uint(mod_time_seconds_since_2000(year, month, mday, hours, minutes, seconds));
+    return mp_obj_new_int_from_uint(timeutils_mktime(mp_obj_get_int(elem[0]),
+            mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]), mp_obj_get_int(elem[3]),
+            mp_obj_get_int(elem[4]), mp_obj_get_int(elem[5])));
 }
 MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime);
 
@@ -328,7 +139,7 @@ STATIC mp_obj_t time_time(void) {
     RTC_TimeTypeDef time;
     HAL_RTC_GetTime(&RTCHandle, &time, FORMAT_BIN);
     HAL_RTC_GetDate(&RTCHandle, &date, FORMAT_BIN);
-    return mp_obj_new_int(mod_time_seconds_since_2000(2000 + date.Year, date.Month, date.Date, time.Hours, time.Minutes, time.Seconds));
+    return mp_obj_new_int(timeutils_seconds_since_2000(2000 + date.Year, date.Month, date.Date, time.Hours, time.Minutes, time.Seconds));
 }
 MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time);
 
diff --git a/stmhal/portmodules.h b/stmhal/portmodules.h
index 66354f7723c461d35f540975c20051f9258271e7..8c2ee6bf87b62888746643750e09798f31724fe2 100644
--- a/stmhal/portmodules.h
+++ b/stmhal/portmodules.h
@@ -34,5 +34,3 @@ extern const mp_obj_module_t mp_module_usocket;
 // additional helper functions exported by the modules
 
 MP_DECLARE_CONST_FUN_OBJ(mod_os_sync_obj);
-
-mp_uint_t mod_time_seconds_since_2000(mp_uint_t year, mp_uint_t month, mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second);