]> git.proxmox.com Git - mirror_edk2.git/blobdiff - StdLib/LibC/Time/Time.c
Standard Libraries for EDK II.
[mirror_edk2.git] / StdLib / LibC / Time / Time.c
diff --git a/StdLib/LibC/Time/Time.c b/StdLib/LibC/Time/Time.c
new file mode 100644 (file)
index 0000000..3192696
--- /dev/null
@@ -0,0 +1,780 @@
+/**\r
+  Definitions and Implementation for <time.h>.\r
+\r
+  Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials are licensed and made available under\r
+  the terms and conditions of the BSD License that accompanies this distribution.\r
+  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+  Portions derived from the NIH time zone package file, localtime.c,\r
+  which contains the following notice:\r
+\r
+    This file is in the public domain, so clarified as of\r
+    1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).\r
+\r
+  NetBSD: localtime.c,v 1.39 2006/03/22 14:01:30 christos Exp\r
+**/\r
+#include  <Uefi.h>\r
+#include  <Library/UefiLib.h>\r
+#include  <Library/TimerLib.h>\r
+#include  <Library/BaseLib.h>\r
+#include  <Library/UefiRuntimeServicesTableLib.h>\r
+//#include  <Library/UefiRuntimeLib.h>\r
+\r
+#include  <LibConfig.h>\r
+\r
+#include  <errno.h>\r
+#include  <limits.h>\r
+#include  <time.h>\r
+#include  <reentrant.h>\r
+#include  "tzfile.h"\r
+#include  "TimeVals.h"\r
+#include  <MainData.h>\r
+#include  <extern.h>      // Library/include/extern.h: Private to implementation\r
+\r
+#if defined(_MSC_VER)           /* Handle Microsoft VC++ compiler specifics. */\r
+// Keep compiler quiet about casting from function to data pointers\r
+#pragma warning ( disable : 4054 )\r
+#endif  /* defined(_MSC_VER) */\r
+\r
+/* #######################  Private Data  ################################# */\r
+\r
+#if 0\r
+static EFI_TIME TimeBuffer;\r
+\r
+  static  UINT16   MonthOffs[12] = {\r
+     00,\r
+     31,   59,   90,  120,\r
+    151,  181,  212,  243,\r
+    273,  304,  334\r
+  };\r
+  static  clock_t   y2kOffs = 730485;\r
+#endif\r
+\r
+const int  mon_lengths[2][MONSPERYEAR] = {\r
+  { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },\r
+  { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }\r
+};\r
+\r
+const int  year_lengths[2] = {\r
+  DAYSPERNYEAR, DAYSPERLYEAR\r
+};\r
+\r
+\r
+static const char *wday_name[7] = {\r
+  "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"\r
+};\r
+\r
+static const char *mon_name[12] = {\r
+  "Jan", "Feb", "Mar", "Apr", "May", "Jun",\r
+  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"\r
+};\r
+\r
+static int    gmt_is_set;\r
+\r
+/* ###############  Implementation Functions  ############################ */\r
+// Forward reference\r
+static void\r
+localsub(const time_t * const timep, const long   offset, struct tm * const tmp);\r
+\r
+clock_t\r
+EFIAPI\r
+__getCPS(void)\r
+{\r
+  return gMD->ClocksPerSecond;\r
+}\r
+\r
+static void\r
+timesub(\r
+  const time_t        * const timep,\r
+  const long                  offset,\r
+  const struct state  * const sp,\r
+        struct tm     * const tmp\r
+  )\r
+{\r
+  const struct lsinfo *  lp;\r
+  time_t /*INTN*/     days;\r
+  time_t /*INTN*/     rem;\r
+  time_t /*INTN*/      y;\r
+  int      yleap;\r
+  const int *    ip;\r
+  time_t /*INTN*/     corr;\r
+  int      hit;\r
+  int      i;\r
+\r
+  corr = 0;\r
+  hit = 0;\r
+#ifdef ALL_STATE\r
+  i = (sp == NULL) ? 0 : sp->leapcnt;\r
+#endif /* defined ALL_STATE */\r
+#ifndef ALL_STATE\r
+  i = sp->leapcnt;\r
+#endif /* State Farm */\r
+  while (--i >= 0) {\r
+    lp = &sp->lsis[i];\r
+    if (*timep >= lp->ls_trans) {\r
+      if (*timep == lp->ls_trans) {\r
+        hit = ((i == 0 && lp->ls_corr > 0) ||\r
+               lp->ls_corr > sp->lsis[i - 1].ls_corr);\r
+        if (hit)\r
+          while (i > 0                                                &&\r
+                 sp->lsis[i].ls_trans == sp->lsis[i - 1].ls_trans + 1 &&\r
+                 sp->lsis[i].ls_corr  == sp->lsis[i - 1].ls_corr  + 1 )\r
+          {\r
+            ++hit;\r
+            --i;\r
+          }\r
+      }\r
+      corr = lp->ls_corr;\r
+      break;\r
+    }\r
+  }\r
+  days = *timep / SECSPERDAY;\r
+  rem = *timep % SECSPERDAY;\r
+  rem += (offset - corr);\r
+  while (rem < 0) {\r
+    rem += SECSPERDAY;\r
+    --days;\r
+  }\r
+  while (rem >= SECSPERDAY) {\r
+    rem -= SECSPERDAY;\r
+    ++days;\r
+  }\r
+  tmp->tm_hour = (int) (rem / SECSPERHOUR);\r
+  rem = rem % SECSPERHOUR;\r
+  tmp->tm_min = (int) (rem / SECSPERMIN);\r
+  /*\r
+  ** A positive leap second requires a special\r
+  ** representation.  This uses "... ??:59:60" et seq.\r
+  */\r
+  tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;\r
+  tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);\r
+  if (tmp->tm_wday < 0)\r
+    tmp->tm_wday += DAYSPERWEEK;\r
+  y = EPOCH_YEAR;\r
+  while (days < 0 || days >= (LONG32) year_lengths[yleap = isleap(y)]) {\r
+    time_t /*INTN*/  newy;\r
+\r
+    newy = (y + days / DAYSPERNYEAR);\r
+    if (days < 0)\r
+      --newy;\r
+    days -= (newy - y) * DAYSPERNYEAR +\r
+      LEAPS_THRU_END_OF(newy - 1) -\r
+      LEAPS_THRU_END_OF(y - 1);\r
+    y = newy;\r
+  }\r
+  tmp->tm_year = (int)(y - TM_YEAR_BASE);\r
+  tmp->tm_yday = (int) days;\r
+  ip = mon_lengths[yleap];\r
+  for (tmp->tm_mon = 0; days >= (LONG32) ip[tmp->tm_mon]; ++(tmp->tm_mon))\r
+    days = days - (LONG32) ip[tmp->tm_mon];\r
+  tmp->tm_mday = (int) (days + 1);\r
+  tmp->tm_isdst = 0;\r
+#ifdef TM_GMTOFF\r
+  tmp->TM_GMTOFF = offset;\r
+#endif /* defined TM_GMTOFF */\r
+}\r
+\r
+/* ###############  Time Manipulation Functions  ########################## */\r
+\r
+/** The clock function determines the processor time used.\r
+\r
+    @return   The clock function returns the implementation\92s best\r
+              approximation to the processor time used by the program since the\r
+              beginning of an implementation-defined era related only to the\r
+              program invocation.  To determine the time in seconds, the value\r
+              returned by the clock function should be divided by the value of\r
+              the macro CLOCKS_PER_SEC.  If the processor time used is not\r
+              available or its value cannot be represented, the function\r
+              returns the value (clock_t)(-1).\r
+\r
+              On IA32 or X64 platforms, the value returned is the number of\r
+              CPU TimeStamp Counter ticks since the appliation started.\r
+**/\r
+clock_t\r
+EFIAPI\r
+clock(void)\r
+{\r
+  clock_t   temp;\r
+\r
+#ifdef NT32dvm\r
+  temp = 0;\r
+#else\r
+  temp = (clock_t)GetPerformanceCounter();\r
+#endif  /* NT32dvm */\r
+\r
+  return temp - gMD->AppStartTime;\r
+}\r
+\r
+/**\r
+**/\r
+double\r
+EFIAPI\r
+difftime(time_t time1, time_t time0)\r
+{\r
+  return (double)(time1 - time0);\r
+}\r
+\r
+/*\r
+** Adapted from code provided by Robert Elz, who writes:\r
+**  The "best" way to do mktime I think is based on an idea of Bob\r
+**  Kridle's (so its said...) from a long time ago.\r
+**  [kridle@xinet.com as of 1996-01-16.]\r
+**  It does a binary search of the time_t space.  Since time_t's are\r
+**  just 32 bits, its a max of 32 iterations (even at 64 bits it\r
+**  would still be very reasonable).\r
+*/\r
+\r
+#ifndef WRONG\r
+#define WRONG (-1)\r
+#endif /* !defined WRONG */\r
+\r
+/*\r
+** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com).\r
+*/\r
+\r
+static int\r
+increment_overflow(int * number, int delta)\r
+{\r
+  int number0;\r
+\r
+  number0 = *number;\r
+  *number += delta;\r
+  return (*number < number0) != (delta < 0);\r
+}\r
+\r
+static int\r
+normalize_overflow(int * const tensptr, int * const unitsptr, const int base)\r
+{\r
+  register int  tensdelta;\r
+\r
+  tensdelta = (*unitsptr >= 0)  ?\r
+              (*unitsptr / base) : (-1 - (-1 - *unitsptr) / base);\r
+  *unitsptr -= tensdelta * base;\r
+  return increment_overflow(tensptr, tensdelta);\r
+}\r
+\r
+static int\r
+tmcomp(const struct tm * const atmp, const struct tm * const btmp)\r
+{\r
+  register int  result;\r
+\r
+  if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&\r
+      (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&\r
+      (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&\r
+      (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&\r
+      (result = (atmp->tm_min - btmp->tm_min)) == 0)\r
+    result = atmp->tm_sec - btmp->tm_sec;\r
+  return result;\r
+}\r
+\r
+static time_t\r
+time2sub(\r
+  struct tm * const tmp,\r
+  void (* const funcp)(const time_t*, long, struct tm*),\r
+  const long offset,\r
+  int * const okayp,\r
+  const int do_norm_secs\r
+  )\r
+{\r
+  register const struct state * sp;\r
+  register int                  dir;\r
+  register int                  bits;\r
+  register int                  i, j ;\r
+  register int                  saved_seconds;\r
+  time_t                        newt;\r
+  time_t                        t;\r
+  struct tm                     yourtm, mytm;\r
+\r
+  *okayp = FALSE;\r
+  yourtm = *tmp;    // Create a copy of tmp\r
+  if (do_norm_secs) {\r
+    if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,\r
+                           SECSPERMIN))\r
+      return WRONG;\r
+  }\r
+  if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))\r
+    return WRONG;\r
+  if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))\r
+    return WRONG;\r
+  if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR))\r
+    return WRONG;\r
+  /*\r
+  ** Turn yourtm.tm_year into an actual year number for now.\r
+  ** It is converted back to an offset from TM_YEAR_BASE later.\r
+  */\r
+  if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE))\r
+    return WRONG;\r
+  while (yourtm.tm_mday <= 0) {\r
+    if (increment_overflow(&yourtm.tm_year, -1))\r
+      return WRONG;\r
+    i = yourtm.tm_year + (1 < yourtm.tm_mon);\r
+    yourtm.tm_mday += year_lengths[isleap(i)];\r
+  }\r
+  while (yourtm.tm_mday > DAYSPERLYEAR) {\r
+    i = yourtm.tm_year + (1 < yourtm.tm_mon);\r
+    yourtm.tm_mday -= year_lengths[isleap(i)];\r
+    if (increment_overflow(&yourtm.tm_year, 1))\r
+      return WRONG;\r
+  }\r
+  for ( ; ; ) {\r
+    i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon];\r
+    if (yourtm.tm_mday <= i)\r
+      break;\r
+    yourtm.tm_mday -= i;\r
+    if (++yourtm.tm_mon >= MONSPERYEAR) {\r
+      yourtm.tm_mon = 0;\r
+      if (increment_overflow(&yourtm.tm_year, 1))\r
+        return WRONG;\r
+    }\r
+  }\r
+  if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE))\r
+    return WRONG;\r
+  if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)\r
+    saved_seconds = 0;\r
+  else if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) {\r
+    /*\r
+    ** We can't set tm_sec to 0, because that might push the\r
+    ** time below the minimum representable time.\r
+    ** Set tm_sec to 59 instead.\r
+    ** This assumes that the minimum representable time is\r
+    ** not in the same minute that a leap second was deleted from,\r
+    ** which is a safer assumption than using 58 would be.\r
+    */\r
+    if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))\r
+      return WRONG;\r
+    saved_seconds = yourtm.tm_sec;\r
+    yourtm.tm_sec = SECSPERMIN - 1;\r
+  } else {\r
+    saved_seconds = yourtm.tm_sec;\r
+    yourtm.tm_sec = 0;\r
+  }\r
+  /*\r
+  ** Divide the search space in half\r
+  ** (this works whether time_t is signed or unsigned).\r
+  */\r
+  bits = TYPE_BIT(time_t) - 1;\r
+  /*\r
+  ** Set t to the midpoint of our binary search.\r
+  **\r
+  ** If time_t is signed, then 0 is just above the median,\r
+  ** assuming two's complement arithmetic.\r
+  ** If time_t is unsigned, then (1 << bits) is just above the median.\r
+  */\r
+  t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits);\r
+  for ( ; ; ) {\r
+    (*funcp)(&t, offset, &mytm);    // Convert t to broken-down time in mytm\r
+    dir = tmcomp(&mytm, &yourtm);   // Is mytm larger, equal, or less than yourtm?\r
+    if (dir != 0) {                 // If mytm != yourtm...\r
+      if (bits-- < 0)                   // If we have exhausted all the bits..\r
+        return WRONG;                       // Return that we failed\r
+      if (bits < 0)                     // If on the last bit...\r
+        --t; /* may be needed if new t is minimal */\r
+      else if (dir > 0)                 // else if mytm > yourtm...\r
+        t -= ((time_t) 1) << bits;          // subtract half the remaining time-space\r
+      else  t += ((time_t) 1) << bits;      // otherwise add half the remaining time-space\r
+      continue;                     // Repeat for the next half\r
+    }\r
+    if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)\r
+      break;\r
+    /*\r
+    ** Right time, wrong type.\r
+    ** Hunt for right time, right type.\r
+    ** It's okay to guess wrong since the guess\r
+    ** gets checked.\r
+    */\r
+    /*\r
+    ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.\r
+    */\r
+    sp = (const struct state *)\r
+      (((void *) funcp == (void *) localsub) ?\r
+       lclptr : gmtptr);\r
+#ifdef ALL_STATE\r
+    if (sp == NULL)\r
+      return WRONG;\r
+#endif /* defined ALL_STATE */\r
+    for (i = sp->typecnt - 1; i >= 0; --i) {\r
+      if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)\r
+        continue;\r
+      for (j = sp->typecnt - 1; j >= 0; --j) {\r
+        if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)\r
+          continue;\r
+        newt = t + sp->ttis[j].tt_gmtoff -\r
+          sp->ttis[i].tt_gmtoff;\r
+        (*funcp)(&newt, offset, &mytm);\r
+        if (tmcomp(&mytm, &yourtm) != 0)\r
+          continue;\r
+        if (mytm.tm_isdst != yourtm.tm_isdst)\r
+          continue;\r
+        /*\r
+        ** We have a match.\r
+        */\r
+        t = newt;\r
+        goto label;\r
+      }\r
+    }\r
+    return WRONG;\r
+  }\r
+  label:\r
+  newt = t + saved_seconds;\r
+  if ((newt < t) != (saved_seconds < 0))\r
+    return WRONG;\r
+  t = newt;\r
+  (*funcp)(&t, offset, tmp);\r
+  *okayp = TRUE;\r
+  return t;\r
+}\r
+\r
+static time_t\r
+time2(struct tm * const tmp, void (* const funcp)(const time_t*, long, struct tm*),\r
+      const long offset, int * const okayp)\r
+{\r
+  time_t  t;\r
+\r
+  /*\r
+  ** First try without normalization of seconds\r
+  ** (in case tm_sec contains a value associated with a leap second).\r
+  ** If that fails, try with normalization of seconds.\r
+  */\r
+  t = time2sub(tmp, funcp, offset, okayp, FALSE);\r
+  return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE);\r
+}\r
+\r
+static time_t\r
+time1(\r
+  struct tm * const tmp,\r
+  void (* const funcp)(const time_t *, long, struct tm *),\r
+  const long offset\r
+  )\r
+{\r
+  register time_t               t;\r
+  register const struct state * sp;\r
+  register int                  samei, otheri;\r
+  register int                  sameind, otherind;\r
+  register int                  i;\r
+  register int                  nseen;\r
+  int                           seen[TZ_MAX_TYPES];\r
+  int                           types[TZ_MAX_TYPES];\r
+  int                           okay;\r
+\r
+  if (tmp->tm_isdst > 1)\r
+    tmp->tm_isdst = 1;\r
+  t = time2(tmp, funcp, offset, &okay);\r
+#ifdef PCTS\r
+  /*\r
+  ** PCTS code courtesy Grant Sullivan (grant@osf.org).\r
+  */\r
+  if (okay)\r
+    return t;\r
+  if (tmp->tm_isdst < 0)\r
+    tmp->tm_isdst = 0;  /* reset to std and try again */\r
+#endif /* defined PCTS */\r
+#ifndef PCTS\r
+  if (okay || tmp->tm_isdst < 0)\r
+    return t;\r
+#endif /* !defined PCTS */\r
+  /*\r
+  ** We're supposed to assume that somebody took a time of one type\r
+  ** and did some math on it that yielded a "struct tm" that's bad.\r
+  ** We try to divine the type they started from and adjust to the\r
+  ** type they need.\r
+  */\r
+  /*\r
+  ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.\r
+  */\r
+  sp = (const struct state *) (((void *) funcp == (void *) localsub) ?\r
+                               lclptr : gmtptr);\r
+#ifdef ALL_STATE\r
+  if (sp == NULL)\r
+    return WRONG;\r
+#endif /* defined ALL_STATE */\r
+  for (i = 0; i < sp->typecnt; ++i)\r
+    seen[i] = FALSE;\r
+  nseen = 0;\r
+  for (i = sp->timecnt - 1; i >= 0; --i)\r
+    if (!seen[sp->types[i]]) {\r
+    seen[sp->types[i]] = TRUE;\r
+    types[nseen++] = sp->types[i];\r
+    }\r
+    for (sameind = 0; sameind < nseen; ++sameind) {\r
+      samei = types[sameind];\r
+      if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)\r
+        continue;\r
+      for (otherind = 0; otherind < nseen; ++otherind) {\r
+        otheri = types[otherind];\r
+        if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)\r
+          continue;\r
+        tmp->tm_sec += (int)(sp->ttis[otheri].tt_gmtoff -\r
+                             sp->ttis[samei].tt_gmtoff);\r
+        tmp->tm_isdst = !tmp->tm_isdst;\r
+        t = time2(tmp, funcp, offset, &okay);\r
+        if (okay)\r
+          return t;\r
+        tmp->tm_sec -= (int)(sp->ttis[otheri].tt_gmtoff -\r
+                             sp->ttis[samei].tt_gmtoff);\r
+        tmp->tm_isdst = !tmp->tm_isdst;\r
+      }\r
+    }\r
+    return WRONG;\r
+}\r
+\r
+/** The mktime function converts the broken-down time, expressed as local time,\r
+    in the structure pointed to by timeptr into a calendar time value with the\r
+    same encoding as that of the values returned by the time function.  The\r
+    original values of the tm_wday and tm_yday components of the structure are\r
+    ignored, and the original values of the other components are not restricted\r
+    to the ranges indicated above.  Thus, a positive or zero value for tm_isdst\r
+    causes the mktime function to presume initially that Daylight Saving Time,\r
+    respectively, is or is not in effect for the specified time. A negative\r
+    value causes it to attempt to determine whether Daylight Saving Time is in\r
+    effect for the specified time.  On successful completion, the values of the\r
+    tm_wday and tm_yday components of the structure are set appropriately, and\r
+    the other components are set to represent the specified calendar time, but\r
+    with their values forced to the ranges indicated above; the final value of\r
+    tm_mday is not set until tm_mon and tm_year are determined.\r
+\r
+    @return   The mktime function returns the specified calendar time encoded\r
+              as a value of type time_t.  If the calendar time cannot be\r
+              represented, the function returns the value (time_t)(-1).\r
+**/\r
+time_t\r
+EFIAPI\r
+mktime(struct tm *timeptr)\r
+{\r
+  /* From NetBSD */\r
+  time_t result;\r
+\r
+  rwlock_wrlock(&lcl_lock);\r
+  tzset();\r
+  result = time1(timeptr, &localsub, 0L);\r
+  rwlock_unlock(&lcl_lock);\r
+  return (result);\r
+}\r
+\r
+/** The time function determines the current calendar time.  The encoding of\r
+    the value is unspecified.\r
+\r
+    @return   The time function returns the implementation\92s best approximation\r
+              to the current calendar time.  The value (time_t)(-1) is returned\r
+              if the calendar time is not available.  If timer is not a null\r
+              pointer, the return value is also assigned to the object it\r
+              points to.\r
+**/\r
+time_t\r
+EFIAPI\r
+time(time_t *timer)\r
+{\r
+  time_t      CalTime;\r
+  EFI_STATUS  Status;\r
+  EFI_TIME   *ET;\r
+  struct tm  *BT;\r
+\r
+  ET = &gMD->TimeBuffer;\r
+  BT = &gMD->BDTime;\r
+\r
+  // Get EFI Time\r
+  Status = gRT->GetTime( ET, NULL);\r
+//  Status = EfiGetTime( ET, NULL);\r
+  EFIerrno = Status;\r
+  if( Status != RETURN_SUCCESS) {\r
+    return (time_t)-1;\r
+  }\r
+\r
+  // Convert EFI time to broken-down time.\r
+  Efi2Tm( ET, BT);\r
+\r
+  // Convert to time_t\r
+  CalTime  =  mktime(&gMD->BDTime);\r
+\r
+  if( timer != NULL) {\r
+    *timer = CalTime;\r
+  }\r
+  return CalTime;   // Return calendar time in microseconds\r
+}\r
+\r
+/* #################  Time Conversion Functions  ########################## */\r
+/*\r
+    Except for the strftime function, these functions each return a pointer to\r
+    one of two types of static objects: a broken-down time structure or an\r
+    array of char.  Execution of any of the functions that return a pointer to\r
+    one of these object types may overwrite the information in any object of\r
+    the same type pointed to by the value returned from any previous call to\r
+    any of them.  The implementation shall behave as if no other library\r
+    functions call these functions.\r
+*/\r
+\r
+/** The asctime function converts the broken-down time in the structure pointed\r
+    to by timeptr into a string in the form\r
+      Sun Sep 16 01:03:52 1973\n\0\r
+    using the equivalent of the following algorithm.\r
+\r
+      char *asctime(const struct tm *timeptr)\r
+      {\r
+        static const char wday_name[7][3] = {\r
+          "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"\r
+        };\r
+        static const char mon_name[12][3] = {\r
+          "Jan", "Feb", "Mar", "Apr", "May", "Jun",\r
+          "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"\r
+        };\r
+        static char result[26];\r
+        sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",\r
+                wday_name[timeptr->tm_wday],\r
+                mon_name[timeptr->tm_mon],\r
+                timeptr->tm_mday, timeptr->tm_hour,\r
+                timeptr->tm_min, timeptr->tm_sec,\r
+                1900 + timeptr->tm_year);\r
+        return result;\r
+      }\r
+    @return   The asctime function returns a pointer to the string.\r
+**/\r
+char *\r
+EFIAPI\r
+asctime(const struct tm *timeptr)\r
+{\r
+  register const char * wn;\r
+  register const char * mn;\r
+\r
+  if (timeptr->tm_wday < 0 || timeptr->tm_wday >= DAYSPERWEEK)\r
+    wn = "???";\r
+  else  wn = wday_name[timeptr->tm_wday];\r
+  if (timeptr->tm_mon < 0 || timeptr->tm_mon >= MONSPERYEAR)\r
+    mn = "???";\r
+  else  mn = mon_name[timeptr->tm_mon];\r
+  /*\r
+  ** The X3J11-suggested format is\r
+  **  "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %d\n"\r
+  ** Since the .2 in 02.2d is ignored, we drop it.\r
+  */\r
+  (void)snprintf(gMD->ASasctime,\r
+                 sizeof (char[ASCTIME_BUFLEN]),\r
+                 "%.3s %.3s%3d %02d:%02d:%02d %d\r\n",    // explicit CRLF for EFI\r
+                 wn, mn,\r
+                 timeptr->tm_mday, timeptr->tm_hour,\r
+                 timeptr->tm_min, timeptr->tm_sec,\r
+                 TM_YEAR_BASE + timeptr->tm_year);\r
+  return gMD->ASasctime;\r
+}\r
+\r
+/**\r
+**/\r
+char *\r
+EFIAPI\r
+ctime(const time_t *timer)\r
+{\r
+  return asctime(localtime(timer));\r
+}\r
+\r
+/*\r
+** gmtsub is to gmtime as localsub is to localtime.\r
+*/\r
+static void\r
+gmtsub(\r
+  const time_t * const  timep,\r
+  const long            offset,\r
+  struct tm    * const  tmp\r
+  )\r
+{\r
+#ifdef _REENTRANT\r
+  static mutex_t gmt_mutex = MUTEX_INITIALIZER;\r
+#endif\r
+\r
+  mutex_lock(&gmt_mutex);\r
+  if (!gmt_is_set) {\r
+    gmt_is_set = TRUE;\r
+#ifdef ALL_STATE\r
+    gmtptr = (struct state *) malloc(sizeof *gmtptr);\r
+    if (gmtptr != NULL)\r
+#endif /* defined ALL_STATE */\r
+      gmtload(gmtptr);\r
+  }\r
+  mutex_unlock(&gmt_mutex);\r
+  timesub(timep, offset, gmtptr, tmp);\r
+#ifdef TM_ZONE\r
+  /*\r
+  ** Could get fancy here and deliver something such as\r
+  ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,\r
+  ** but this is no time for a treasure hunt.\r
+  */\r
+  if (offset != 0)\r
+    tmp->TM_ZONE = (__aconst char *)__UNCONST(wildabbr);\r
+  else {\r
+#ifdef ALL_STATE\r
+    if (gmtptr == NULL)\r
+      tmp->TM_ZONE = (__aconst char *)__UNCONST(gmt);\r
+    else  tmp->TM_ZONE = gmtptr->chars;\r
+#endif /* defined ALL_STATE */\r
+#ifndef ALL_STATE\r
+    tmp->TM_ZONE = gmtptr->chars;\r
+#endif /* State Farm */\r
+  }\r
+#endif /* defined TM_ZONE */\r
+}\r
+\r
+/**\r
+**/\r
+struct tm *\r
+EFIAPI\r
+gmtime(const time_t *timer)\r
+{\r
+  gmtsub(timer, 0L, &gMD->BDTime);\r
+  return &gMD->BDTime;\r
+}\r
+\r
+static void\r
+localsub(const time_t * const timep, const long   offset, struct tm * const tmp)\r
+{\r
+  register struct state *   sp;\r
+  register const struct ttinfo *  ttisp;\r
+  register int      i;\r
+  const time_t      t = *timep;\r
+\r
+  sp = lclptr;\r
+#ifdef ALL_STATE\r
+  if (sp == NULL) {\r
+    gmtsub(timep, offset, tmp);\r
+    return;\r
+  }\r
+#endif /* defined ALL_STATE */\r
+  if (sp->timecnt == 0 || t < sp->ats[0]) {\r
+    i = 0;\r
+    while (sp->ttis[i].tt_isdst)\r
+      if (++i >= sp->typecnt) {\r
+        i = 0;\r
+        break;\r
+      }\r
+  } else {\r
+    for (i = 1; i < sp->timecnt; ++i)\r
+      if (t < sp->ats[i])\r
+      break;\r
+    i = sp->types[i - 1];\r
+  }\r
+  ttisp = &sp->ttis[i];\r
+  /*\r
+  ** To get (wrong) behavior that's compatible with System V Release 2.0\r
+  ** you'd replace the statement below with\r
+  **  t += ttisp->tt_gmtoff;\r
+  **  timesub(&t, 0L, sp, tmp);\r
+  */\r
+  timesub(&t, ttisp->tt_gmtoff, sp, tmp);\r
+  tmp->tm_isdst = ttisp->tt_isdst;\r
+  tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];\r
+#ifdef TM_ZONE\r
+  tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];\r
+#endif /* defined TM_ZONE */\r
+}\r
+\r
+/**\r
+**/\r
+struct tm *\r
+EFIAPI\r
+localtime(const time_t *timer)\r
+{\r
+  tzset();\r
+  localsub(timer, 0L, &gMD->BDTime);\r
+  return &gMD->BDTime;\r
+}\r