From 49a834785b94f0e2c5c9bfab628377103bd3db41 Mon Sep 17 00:00:00 2001 From: patacongo Date: Sun, 12 Jul 2009 15:16:00 +0000 Subject: [PATCH] Add strftime git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@1977 42af7a65-404d-4744-a932-0658087f49c3 --- include/nuttx/time.h | 17 +- include/time.h | 11 +- lib/Makefile | 3 +- lib/{lib_timeutils.c => lib_calendar2utc.c} | 27 +- lib/lib_daysbeforemonth.c | 99 +++++ lib/lib_gmtimer.c | 67 +++- lib/lib_isleapyear.c | 88 +++++ lib/lib_mktime.c | 15 +- lib/lib_strftime.c | 389 ++++++++++++++++++++ 9 files changed, 654 insertions(+), 62 deletions(-) rename lib/{lib_timeutils.c => lib_calendar2utc.c} (91%) create mode 100644 lib/lib_daysbeforemonth.c create mode 100644 lib/lib_isleapyear.c create mode 100644 lib/lib_strftime.c diff --git a/include/nuttx/time.h b/include/nuttx/time.h index 1e5e50cb52..837e3a1801 100644 --- a/include/nuttx/time.h +++ b/include/nuttx/time.h @@ -42,6 +42,7 @@ #include #include +#include /**************************************************************************** * 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 ce18c13501..bffde1041a 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 63264bc36f..0255234ac8 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 31404edded..ead92958fb 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 0000000000..e9c4d0026b --- /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 + * + * 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 +#include +#include + +/**************************************************************************** + * 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 2758acd1a7..03e1a20588 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 0000000000..f27f141093 --- /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 + * + * 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 +#include +#include + +/**************************************************************************** + * 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 594a0672b0..46e16c50f5 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 0000000000..02cce388be --- /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 + * + * 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 +#include + +#include +#include +#include + +#include + +/**************************************************************************** + * 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; +}