Small test of the gmtime function.

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
bjblazkowicz
Date:
Sun May 10 22:05:28 2015 +0000
Commit message:
Initial commit.

Changed in this revision

gmtime_newlib.cpp Show annotated file Show diff for this revision Revisions of this file
gmtime_newlib.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gmtime_newlib.cpp	Sun May 10 22:05:28 2015 +0000
@@ -0,0 +1,159 @@
+/*
+ * gmtime_r.c
+ * Original Author: Adapted from tzcode maintained by Arthur David Olson.
+ * Modifications:
+ * - Changed to mktm_r and added __tzcalc_limits - 04/10/02, Jeff Johnston
+ * - Fixed bug in mday computations - 08/12/04, Alex Mogilnikov <alx@intellectronika.ru>
+ * - Fixed bug in __tzcalc_limits - 08/12/04, Alex Mogilnikov <alx@intellectronika.ru>
+ * - Move code from _mktm_r() to gmtime_r() - 05/09/14, Freddie Chopin <freddie_chopin@op.pl>
+ * - Fixed bug in calculations for dates after year 2069 or before year 1901. Ideas for
+ *   solution taken from musl's __secs_to_tm() - 07/12/2014, Freddie Chopin
+ *   <freddie_chopin@op.pl>
+ *
+ * Converts the calendar time pointed to by tim_p into a broken-down time
+ * expressed as local time. Returns a pointer to a structure containing the
+ * broken-down time.
+ */
+ 
+// *** ChrisP 5/10/15: Code taken from http://sourceware.org/newlib/; modified slightly to compile on mbed.org ***
+
+#include "mbed.h"
+
+/* move epoch from 01.01.1970 to 01.03.2000 - this is the first day of new
+ * 400-year long cycle, right after additional day of leap year. This adjustment
+ * is required only for date calculation, so instead of modifying time_t value
+ * (which would require 64-bit operations to work correctly) it's enough to
+ * adjust the calculated number of days since epoch. */
+#define EPOCH_ADJUSTMENT_DAYS   11017
+/* year to which the adjustment was made */
+#define ADJUSTED_EPOCH_YEAR 2000
+/* 1st March of 2000 is Wednesday */
+#define ADJUSTED_EPOCH_WDAY 3
+/* there are 97 leap years in 400-year periods. ((400 - 97) * 365 + 97 * 366) */
+#define DAYS_PER_400_YEARS  146097L
+/* there are 24 leap years in 100-year periods. ((100 - 24) * 365 + 24 * 366) */
+#define DAYS_PER_100_YEARS  36524L
+/* there is one leap year every 4 years */
+#define DAYS_PER_4_YEARS    (3 * 365 + 366)
+/* number of days in a non-leap year */
+#define DAYS_PER_YEAR       365
+/* number of days in January */
+#define DAYS_IN_JANUARY     31
+/* number of days in non-leap February */
+#define DAYS_IN_FEBRUARY    28
+
+#define SECSPERMIN  60L
+#define MINSPERHOUR 60L
+#define HOURSPERDAY 24L
+#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
+#define SECSPERDAY  (SECSPERHOUR * HOURSPERDAY)
+#define DAYSPERWEEK 7
+#define MONSPERYEAR 12
+
+#define YEAR_BASE   1900
+#define EPOCH_YEAR      1970
+#define EPOCH_WDAY      4
+#define EPOCH_YEARS_SINCE_LEAP 2
+#define EPOCH_YEARS_SINCE_CENTURY 70
+#define EPOCH_YEARS_SINCE_LEAP_CENTURY 370
+
+#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
+
+const int __month_lengths[2][MONSPERYEAR] = {
+  {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+  {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
+} ;
+
+struct tm *
+gmtime_newlib(const time_t* tim_p, struct tm* res)
+{
+  long days, rem;
+  const time_t lcltime = *tim_p;
+  int year, month, yearday, weekday;
+  int years400, years100, years4, remainingyears;
+  int yearleap;
+  const int *ip;
+
+  days = ((long)lcltime) / SECSPERDAY - EPOCH_ADJUSTMENT_DAYS;
+  rem = ((long)lcltime) % SECSPERDAY;
+  if (rem < 0)
+    {
+      rem += SECSPERDAY;
+      --days;
+    }
+
+  /* compute hour, min, and sec */
+  res->tm_hour = (int) (rem / SECSPERHOUR);
+  rem %= SECSPERHOUR;
+  res->tm_min = (int) (rem / SECSPERMIN);
+  res->tm_sec = (int) (rem % SECSPERMIN);
+
+  /* compute day of week */
+  if ((weekday = ((ADJUSTED_EPOCH_WDAY + days) % DAYSPERWEEK)) < 0)
+    weekday += DAYSPERWEEK;
+  res->tm_wday = weekday;
+
+  /* compute year & day of year */
+  years400 = days / DAYS_PER_400_YEARS;
+  days -= years400 * DAYS_PER_400_YEARS;
+  /* simplify by making the values positive */
+  if (days < 0)
+    {
+      days += DAYS_PER_400_YEARS;
+      --years400;
+    }
+
+  years100 = days / DAYS_PER_100_YEARS;
+  if (years100 == 4) /* required for proper day of year calculation */
+    --years100;
+  days -= years100 * DAYS_PER_100_YEARS;
+  years4 = days / DAYS_PER_4_YEARS;
+  days -= years4 * DAYS_PER_4_YEARS;
+  remainingyears = days / DAYS_PER_YEAR;
+  if (remainingyears == 4) /* required for proper day of year calculation */
+    --remainingyears;
+  days -= remainingyears * DAYS_PER_YEAR;
+
+  year = ADJUSTED_EPOCH_YEAR + years400 * 400 + years100 * 100 + years4 * 4 +
+      remainingyears;
+
+  /* If remainingyears is zero, it means that the years were completely
+   * "consumed" by modulo calculations by 400, 100 and 4, so the year is:
+   * 1. a multiple of 4, but not a multiple of 100 or 400 - it's a leap year,
+   * 2. a multiple of 4 and 100, but not a multiple of 400 - it's not a leap
+   * year,
+   * 3. a multiple of 4, 100 and 400 - it's a leap year.
+   * If years4 is non-zero, it means that the year is not a multiple of 100 or
+   * 400 (case 1), so it's a leap year. If years100 is zero (and years4 is zero
+   * - due to short-circuiting), it means that the year is a multiple of 400
+   * (case 3), so it's also a leap year. */
+  yearleap = remainingyears == 0 && (years4 != 0 || years100 == 0);
+
+  /* adjust back to 1st January */
+  yearday = days + DAYS_IN_JANUARY + DAYS_IN_FEBRUARY + yearleap;
+  if (yearday >= DAYS_PER_YEAR + yearleap)
+    {
+      yearday -= DAYS_PER_YEAR + yearleap;
+      ++year;
+    }
+  res->tm_yday = yearday;
+  res->tm_year = year - YEAR_BASE;
+
+  /* Because "days" is the number of days since 1st March, the additional leap
+   * day (29th of February) is the last possible day, so it doesn't matter much
+   * whether the year is actually leap or not. */
+  ip = __month_lengths[1];
+  month = 2;
+  while (days >= ip[month])
+    {
+      days -= ip[month];
+      if (++month >= MONSPERYEAR)
+        month = 0;
+    }
+  res->tm_mon = month;
+  res->tm_mday = days + 1;
+
+  res->tm_isdst = 0;
+
+  return (res);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gmtime_newlib.h	Sun May 10 22:05:28 2015 +0000
@@ -0,0 +1,8 @@
+
+#ifndef GMTIME_NEWLIB_H
+#define GMTIME_NEWLIB_H
+
+struct tm *
+gmtime_newlib(const time_t* tim_p, struct tm* res);
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Sun May 10 22:05:28 2015 +0000
@@ -0,0 +1,27 @@
+#include "mbed.h"
+#include "gmtime_newlib.h"
+
+Serial console(USBTX, USBRX);
+
+int main() 
+{
+    console.baud(9600);
+    
+    // Set time to Tue, 10 Nov 2015 14:00:00 GMT
+    set_time(1447164000);
+
+    time_t rawTime;
+    time(&rawTime);
+    
+    // Prints: time_t: 1447164000, h:13773, m:1377, s:537067520
+    struct tm *parsedUsingMbed = gmtime(&rawTime);
+    console.printf("time_t: %d, h:%d, m:%d, s:%d\r\n", rawTime, parsedUsingMbed->tm_hour, parsedUsingMbed->tm_min, parsedUsingMbed->tm_sec);
+
+    // Prints: time_t: 1447164000, h:14, m:0, s:0
+    struct tm parsedUsingNewlib;
+    gmtime_newlib(&rawTime, &parsedUsingNewlib);
+    console.printf("time_t: %d, h:%d, m:%d, s:%d\r\n", rawTime, parsedUsingNewlib.tm_hour, parsedUsingNewlib.tm_min, parsedUsingNewlib.tm_sec);
+
+    while(1)
+        ;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Sun May 10 22:05:28 2015 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/8ab26030e058
\ No newline at end of file