diff --git a/include/nuttx/time.h b/include/nuttx/time.h
index 1e5e50cb523db0b33b791b8494419c7089b1d5d8..837e3a18012bb11726d191d2f30d837ca10d527d 100644
--- a/include/nuttx/time.h
+++ b/include/nuttx/time.h
@@ -42,6 +42,7 @@
 
 #include <nuttx/config.h>
 #include <sys/types.h>
+#include <time.h>
 
 /****************************************************************************
  * Pre-Processor Definitions
@@ -66,10 +67,6 @@
  * Public Data
  ****************************************************************************/
 
-#ifndef CONFIG_GREGORIAN_TIME
-extern uint16 g_daysbeforemonth[13];
-#endif
-
 /****************************************************************************
  * Public Function Prototypes
  ****************************************************************************/
@@ -89,9 +86,17 @@ extern "C" {
  *
  ****************************************************************************/
 
-#ifndef CONFIG_GREGORIAN_TIME
 EXTERN int clock_isleapyear(int year);
-#endif
+
+/****************************************************************************
+ * Function:  clock_daysbeforemonth
+ *
+ * Description:
+ *    Get the number of days that occurred before the beginning of the month.
+ *
+ ****************************************************************************/
+
+EXTERN int clock_daysbeforemonth(int month, boolean leapyear);
 
 /****************************************************************************
  * Function:  clock_calendar2utc
diff --git a/include/time.h b/include/time.h
index ce18c135018747b6c2828c1a5592bb6b9c267191..bffde1041a2fc7e84cccdf15b50ec7d0b2e9fbc5 100644
--- a/include/time.h
+++ b/include/time.h
@@ -73,6 +73,11 @@
 
 #define TIMER_ABSTIME 1
 
+/* Local time is the same as gmtime in this implementation */
+
+#define localtime(c)     gmtime(c)
+#define localtime_r(c,r) gmtime_r(c,r)
+
 /********************************************************************************
  * Global Type Declarations
  ********************************************************************************/
@@ -142,12 +147,10 @@ EXTERN int clock_settime(clockid_t clockid, const struct timespec *tp);
 EXTERN int clock_gettime(clockid_t clockid, struct timespec *tp);
 EXTERN int clock_getres(clockid_t clockid, struct timespec *res);
 
-EXTERN time_t mktime(struct tm *tp);
+EXTERN time_t mktime(const struct tm *tp);
 EXTERN struct tm *gmtime(const time_t *clock);
 EXTERN struct tm *gmtime_r(const time_t *clock, struct tm *result);
-
-#define localtime(c)     gmtime(c)
-#define localtime_r(c,r) gmtime_r(c,r)
+EXTERN size_t strftime(char *s, size_t max, const char *format, const struct tm *tm);
 
 EXTERN int timer_create(clockid_t clockid, FAR struct sigevent *evp, FAR timer_t *timerid);
 EXTERN int timer_delete(timer_t timerid);
diff --git a/lib/Makefile b/lib/Makefile
index 63264bc36f0dbf77cf3273300fef0cb9aea30435..0255234ac8738567fc0e20755e3710bc3061f10f 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -83,7 +83,8 @@ UNISTD_SRCS	+=  lib_chdir.c lib_getcwd.c
 endif
 endif
 
-TIME_SRCS	= lib_mktime.c lib_gmtime.c lib_gmtimer.c lib_timeutils.c
+TIME_SRCS	= lib_mktime.c lib_gmtime.c lib_gmtimer.c lib_strftime.c \
+		  lib_calendar2utc.c lib_daysbeforemonth.c lib_isleapyear.c
 
 NET_SRCS	= lib_htons.c lib_htonl.c lib_inetntoa.c lib_etherntoa.c
 
diff --git a/lib/lib_timeutils.c b/lib/lib_calendar2utc.c
similarity index 91%
rename from lib/lib_timeutils.c
rename to lib/lib_calendar2utc.c
index 31404eddeda8267bd594d0b26137e42e8080548b..ead92958fb552c5c60dcb54f5839a05b9d3aa425 100644
--- a/lib/lib_timeutils.c
+++ b/lib/lib_calendar2utc.c
@@ -65,13 +65,6 @@
  * Public Variables
  ****************************************************************************/
 
-#ifndef CONFIG_GREGORIAN_TIME
-uint16 g_daysbeforemonth[13] =
-{
-  0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
-};
-#endif
-
 /****************************************************************************
  * Private Variables
  ****************************************************************************/
@@ -120,21 +113,6 @@ static time_t clock_julian2utc(int year, int month, int day)
  * Public Functions
  ****************************************************************************/
 
-/****************************************************************************
- * Function:  clock_isleapyear
- *
- * Description:
- *    Return true if the specified year is a leap year
- *
- ****************************************************************************/
-
-#ifndef CONFIG_GREGORIAN_TIME
-int clock_isleapyear(int year)
-{
-  return year % 400 ? (year % 100 ? (year % 4 ? 0 : 1) : 0) : 1;
-}
-#endif /* !CONFIG_GREGORIAN_TIME */
-
 /****************************************************************************
  * Function:  clock_calendar2utc
  *
@@ -208,6 +186,11 @@ time_t clock_calendar2utc(int year, int month, int day)
 #endif /* CONFIG_JULIAN_TIME */
 }
 #else
+
+/* A highly simplified version that only handles days in the time
+ * since Jan 1, 1970.
+ */
+
 time_t clock_calendar2utc(int year, int month, int day)
 {
   struct tm t;
diff --git a/lib/lib_daysbeforemonth.c b/lib/lib_daysbeforemonth.c
new file mode 100644
index 0000000000000000000000000000000000000000..e9c4d0026b656f0cf2732fb84e7d6b076dc358c9
--- /dev/null
+++ b/lib/lib_daysbeforemonth.c
@@ -0,0 +1,99 @@
+/****************************************************************************
+ * lib/lib_daysbeforemonth.c
+ *
+ *   Copyright (C) 2007, 2009 Gregory Nutt. All rights reserved.
+ *   Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <sys/types.h>
+#include <nuttx/time.h>
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Type Declarations
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Constant Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Variables
+ ****************************************************************************/
+
+uint16 g_daysbeforemonth[13] =
+{
+  0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
+};
+
+/****************************************************************************
+ * Private Variables
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Function:  clock_daysbeforemonth
+ *
+ * Description:
+ *    Get the number of days that occurred before the beginning of the month.
+ *
+ ****************************************************************************/
+
+int clock_daysbeforemonth(int month, boolean leapyear)
+{
+  int retval = g_daysbeforemonth[month];
+  if (month >= 2 && leapyear)
+    {
+      retval++;
+    }
+  return retval;
+}
+
+
diff --git a/lib/lib_gmtimer.c b/lib/lib_gmtimer.c
index 2758acd1a7e9276c5817e34dff021fd9e8e9115b..03e1a20588073d82bdaaeed6625b67cbff96b002 100644
--- a/lib/lib_gmtimer.c
+++ b/lib/lib_gmtimer.c
@@ -163,15 +163,26 @@ static void clock_utc2julian(time_t jd, int *year, int *month, int *day)
 #endif /* CONFIG_JULIAN_TIME */
 #else/* CONFIG_GREGORIAN_TIME */
 
+/* Only handles dates since Jan 1, 1970 */
+
 static void clock_utc2calendar(time_t days, int *year, int *month, int *day)
 {
   int     value;
+  int     min;
+  int     max;
   int     tmp;
   boolean leapyear;
 
-  /* There must be a better way to do this than the brute for method below */
+  /* There is one leap year every four years, so we can get close with the
+   * following:
+   */
+
+  value = days  / (4*365 + 1);  /* Number of 4-years periods */
+  days -= value * (4*365 + 1);  /* Remaining days */
+  value = 70 + (value << 2);    /* 1970 plus the 4 year groups */
+
+  /* Then we will brute force the next 0-3 years */
 
-  value = 70;
   for (;;)
     {
       /* Is this year a leap year (we'll need this later too) */
@@ -203,43 +214,63 @@ static void clock_utc2calendar(time_t days, int *year, int *month, int *day)
 
   *year = value;
 
-  /* Handle the month */
+  /* Handle the month (zero based) */
 
-  value = 0; /* zero-based */
-  for (;;)
+  min = 0;
+  max = 11;
+
+  do
     {
-      /* Get the number of days that occurred before the beginning of the next month */
+      /* Get the midpoint */
 
-      tmp = g_daysbeforemonth[value + 1];
-      if (value >= 2 && leapyear)
-        {
-          tmp++;
-        }
+      value = (min + max) >> 1;
+
+      /* Get the number of days that occurred before the beginning month
+       * following the midpoint.
+      */
+
+      tmp = clock_daysbeforemonth(value + 1, leapyear);
 
       /* Does that equal or exceed the number of days we have remaining? */
 
       if (tmp >= days)
         {
-          /* Yes.. this is the one we want.  The 'days' for this number of days that
-           * occurred before this month.
+          /* Yes.. then the month we want is somewhere between 'min' and the.
+           * midpoint, 'value'.  Check if it is the midpoint.
            */
 
-          days -= g_daysbeforemonth[value];
-          break;
+          tmp = clock_daysbeforemonth(value, leapyear);
+          if (tmp >= days)
+            {
+              /* No... The one we want is somewhere between min and value-1 */
+
+              max = value - 1;
+            }
+          else
+            {
+              /* Yes.. 'value' contains the month that we want */
+
+              break;
+            }
         }
       else
         {
-           /* No... try the next month */
+           /* No... The one we want is somwhere between value+1 and max */
 
-           value++;
+           min = value + 1;
         }
     }
+  while (min < max);
+
+  /* Subtract the number of days in the selected month */
+
+  days -= clock_daysbeforemonth(value, leapyear);
 
   /* At this point, value has the month into this year (zero based) and days has
    * number of days into this month (zero based)
    */
 
-  *month = value;
+  *month = value;    /* Zero based */
   *day   = days + 1; /* 1-based */
 }
 
diff --git a/lib/lib_isleapyear.c b/lib/lib_isleapyear.c
new file mode 100644
index 0000000000000000000000000000000000000000..f27f141093c5918cc79978b3fb8c35541a8b6388
--- /dev/null
+++ b/lib/lib_isleapyear.c
@@ -0,0 +1,88 @@
+/****************************************************************************
+ * lib/lib_isleapyear.c
+ *
+ *   Copyright (C) 2009 Gregory Nutt. All rights reserved.
+ *   Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <sys/types.h>
+#include <nuttx/time.h>
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Type Declarations
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Constant Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Variables
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Variables
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Function:  clock_isleapyear
+ *
+ * Description:
+ *    Return true if the specified year is a leap year
+ *
+ ****************************************************************************/
+
+int clock_isleapyear(int year)
+{
+  return year % 400 ? (year % 100 ? (year % 4 ? 0 : 1) : 0) : 1;
+}
+
diff --git a/lib/lib_mktime.c b/lib/lib_mktime.c
index 594a0672b074e23c6e575438f8f226559a1f284a..46e16c50f54f4fa1e6d14578d9bf83bd9f4ce0a7 100644
--- a/lib/lib_mktime.c
+++ b/lib/lib_mktime.c
@@ -86,7 +86,7 @@
  ****************************************************************************/
 
 #ifdef CONFIG_GREGORIAN_TIME
-time_t mktime(struct tm *tp)
+time_t mktime(const struct tm *tp)
 {
   time_t ret;
   time_t jdn;
@@ -114,7 +114,7 @@ time_t mktime(struct tm *tp)
  * seconds, etc. apply.
  */
 
-time_t mktime(struct tm *tp)
+time_t mktime(const struct tm *tp)
 {
   unsigned int days;
 
@@ -126,16 +126,9 @@ time_t mktime(struct tm *tp)
 
   days += (tp->tm_year - 69) >> 2;
 
-  /* Add in the days up to the beginning of this month (ignoring any possible leap day). */
+  /* Add in the days up to the beginning of this month. */
 
-  days += (time_t)g_daysbeforemonth[tp->tm_mon];
-
-  /* Add in the leap day for this year (months are zero based) */
-
-  if (tp->tm_mon >= 2 && clock_isleapyear(tp->tm_year + 1900))
-    {
-      days++;
-    }
+  days += (time_t)clock_daysbeforemonth(tp->tm_mon, clock_isleapyear(tp->tm_year + 1900));
 
   /* Add in the days since the beginning of this month (days are 1-based). */
 
diff --git a/lib/lib_strftime.c b/lib/lib_strftime.c
new file mode 100644
index 0000000000000000000000000000000000000000..02cce388be0447f05777597f10bcd1a6467e0fef
--- /dev/null
+++ b/lib/lib_strftime.c
@@ -0,0 +1,389 @@
+/****************************************************************************
+ * lib/lib_strftime.c
+ *
+ *   Copyright (C) 2007, 2009 Gregory Nutt. All rights reserved.
+ *   Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <time.h>
+#include <debug.h>
+
+#include <nuttx/time.h>
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Type Declarations
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Constant Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const char *g_abbrevmonthname[12] =
+{
+  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+static const char *g_monthname[12] =
+{
+  "January", "February", "March",     "April",   "May",      "June",
+  "July",    "August",   "September", "October", "November", "December"
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Function:  strftime
+ *
+ * Description:
+ *   The  strftime()  function  formats the broken-down time tm according to
+ *   the format specification format and places the result in the  character
+ *   array s of size max.
+ *
+ *   Ordinary characters placed in the format string are copied to s without
+ *   conversion.  Conversion specifications are introduced by a '%'  charac-
+ *   ter,  and  terminated  by  a  conversion  specifier  character, and are
+ *   replaced in s as follows:
+ *
+ *   %b     The abbreviated month name according to the current locale.
+ *   %B     The full month name according to the current locale.
+ *   %C     The century number (year/100) as a 2-digit integer. (SU)
+ *   %d     The day of the month as a decimal number (range 01 to 31).
+ *   %e     Like %d, the day of the month as a decimal number, but a leading
+ *          zero is replaced by a space.
+ *   %h     Equivalent to %b.  (SU)
+ *   %H     The hour as a decimal number using a 24-hour clock (range 00 to 23).
+ *   %I     The  hour as a decimal number using a 12-hour clock (range 01 to 12).
+ *   %j     The day of the year as a decimal number (range 001 to 366).
+ *   %k     The hour (24-hour clock) as a decimal number (range  0  to  23);
+ *          single digits are preceded by a blank.  (See also %H.)  (TZ)
+ *   %l     The  hour  (12-hour  clock) as a decimal number (range 1 to 12);
+ *          single digits are preceded by a blank.  (See also %I.)  (TZ)
+ *   %m     The month as a decimal number (range 01 to 12).
+ *   %M     The minute as a decimal number (range 00 to 59).
+ *   %n     A newline character. (SU)
+ *   %p     Either "AM" or "PM" according to the given time  value, or the
+ *          corresponding  strings  for the current locale.  Noon is treated
+ *          as "PM" and midnight as "AM".
+ *   %P     Like %p but in lowercase: "am" or "pm" or a corresponding string
+ *          for the current locale. (GNU)
+ *   %s     The number of seconds since the Epoch, that is, since 1970-01-01
+ *          00:00:00 UTC. (TZ)
+ *   %S     The second as a decimal number (range 00 to 60).  (The range is
+ *          up to 60 to allow for occasional leap seconds.)
+ *   %t     A tab character. (SU)
+ *   %y     The year as a decimal number without a century (range 00 to 99).
+ *   %Y     The year as a decimal number including the century.
+ *   %%     A literal '%' character.
+ *
+ * Returned Value:
+ *   The strftime() function returns the number of characters placed in  the
+ *    array s, not including the terminating null byte, provided the string,
+ *    including the terminating null byte, fits.  Otherwise,  it returns 0,
+ *    and the contents of the array is undefined. 
+ *
+ ****************************************************************************/
+
+size_t strftime(char *s, size_t max, const char *format, const struct tm *tm)
+{
+  const char *str;
+  char       *dest   = s;
+  int         chleft = max;
+  int         value;
+  int         len;
+
+  while (*format && chleft > 0)
+    {
+      /* Just copy regular characters */
+
+      if (*format != '%')
+        {
+           *dest++ = *format++;
+           chleft--;
+           continue;
+        }
+
+      /* Handle the format character */
+
+       len   = 0;
+       value = 0;
+       str   = "??";
+
+       switch (*++format)
+         {
+           /* %h: Equivalent to %b */
+
+           case 'h':
+
+           /* %b: The abbreviated month name according to the current locale. */
+
+           case 'b':
+             {
+               if (tm->tm_mon < 12)
+                 {
+                   str = g_abbrevmonthname[tm->tm_mon];
+                 }
+               len = snprintf(dest, chleft, "%s", str);
+             }
+             break;
+
+           /* %B: The full month name according to the current locale. */
+
+           case 'B':
+             {
+               if (tm->tm_mon < 12)
+                 {
+                   str = g_monthname[tm->tm_mon];
+                 }
+               len = snprintf(dest, chleft, "%s", str);
+             }
+             break;
+
+           /* %y: The year as a decimal number without a century (range 00 to 99). */
+
+           case 'y':
+
+           /* %C: The century number (year/100) as a 2-digit integer. */
+
+           case 'C':
+             {
+               len = snprintf(dest, chleft, "%02d", tm->tm_year);
+             }
+             break;
+
+           /* %d: The day of the month as a decimal number (range 01 to 31). */
+
+           case 'd':
+             {
+               len = snprintf(dest, chleft, "%02d", tm->tm_mday);
+             }
+             break;
+
+           /* %e: Like %d, the day of the month as a decimal number, but a leading
+            * zero is replaced by a space.
+            */
+
+           case 'e':
+             {
+               len = snprintf(dest, chleft, "%2d", tm->tm_mday);
+             }
+             break;
+
+           /* %H: The hour as a decimal number using a 24-hour clock (range 00  to 23). */
+
+           case 'H':
+             {
+               len = snprintf(dest, chleft, "%02d", tm->tm_hour);
+             }
+             break;
+
+           /* %I: The  hour as a decimal number using a 12-hour clock (range 01 to 12). */
+
+           case 'I':
+             {
+               len = snprintf(dest, chleft, "%02d", tm->tm_hour % 12);
+             }
+             break;
+
+           /* %j: The day of the year as a decimal number (range 001 to 366). */
+
+           case 'j':
+             {
+               if (tm->tm_mon < 12)
+                 {
+                   value = clock_daysbeforemonth(tm->tm_mon, clock_isleapyear(tm->tm_year)) + tm->tm_mday;
+                 }
+               len = snprintf(dest, chleft, "%03d", value);
+             }
+             break;
+
+           /* %k: The hour (24-hour clock) as a decimal number (range  0  to  23);
+            * single digits are preceded by a blank.
+            */
+
+           case 'k':
+             {
+               len = snprintf(dest, chleft, "%2d", tm->tm_hour);
+             }
+             break;
+
+           /* %l: The  hour  (12-hour  clock) as a decimal number (range 1 to 12);
+            * single digits are preceded by a blank.
+            */
+
+           case 'l':
+             {
+               len = snprintf(dest, chleft, "%2d", tm->tm_hour % 12);
+             }
+             break;
+
+           /* %m: The month as a decimal number (range 01 to 12). */
+
+           case 'm':
+             {
+               len = snprintf(dest, chleft, "%02d", tm->tm_mon + 1);
+             }
+             break;
+
+           /* %M: The minute as a decimal number (range 00 to 59). */
+
+           case 'M':
+             {
+               len = snprintf(dest, chleft, "%02d", tm->tm_min);
+             }
+             break;
+
+           /* %n: A newline character. */
+
+           case 'n':
+             {
+               *dest = '\n';
+               len   = 1;
+             }
+             break;
+
+           /* %p: Either "AM" or "PM" according to the given time  value. */
+
+           case 'p':
+             {
+               if (tm->tm_hour >= 12)
+                 {
+                   str = "PM";
+                 }
+               else
+                 {
+                   str = "AM";
+                 }
+               len = snprintf(dest, chleft, "%s", str);
+             }
+             break;
+
+           /* %P: Like %p but in lowercase: "am" or "pm" */
+
+           case 'P':
+             {
+               if (tm->tm_hour >= 12)
+                 {
+                   str = "pm";
+                 }
+               else
+                 {
+                   str = "am";
+                 }
+               len = snprintf(dest, chleft, "%s", str);
+             }
+             break;
+
+           /* %s: The number of seconds since the Epoch, that is, since 1970-01-01
+            * 00:00:00 UTC.
+            */
+
+           case 's':
+             {
+               len = snprintf(dest, chleft, "%d", mktime(tm));
+             }
+             break;
+
+           /* %S: The second as a decimal number (range 00 to 60).  (The range  is
+            * up to 60 to allow for occasional leap seconds.)
+            */
+
+           case 'S':
+             {
+               len = snprintf(dest, chleft, "%02d", tm->tm_sec);
+             }
+             break;
+
+           /* %t: A tab character. */
+
+           case 't':
+             {
+               *dest = '\t';
+               len   = 1;
+             }
+             break;
+
+           /* %Y: The year as a decimal number including the century. */
+
+           case 'Y':
+             {
+               len = snprintf(dest, chleft, "%04d", tm->tm_year + 1900);
+             }
+             break;
+
+           /* %%:  A literal '%' character. */
+
+           case '%':
+             {
+               *dest = '%';
+               len   = 1;
+             }
+             break;
+        }
+
+      /* Update counts and pointers */
+
+      dest   += len;
+      chleft -= len;
+    }
+
+  return max - chleft;
+}