Home | History | Annotate | Download | only in EfiTimeBaseLib
      1 /** @file
      2 *
      3 *  Copyright (c) 2016, Hisilicon Limited. All rights reserved.
      4 *  Copyright (c) 2016, Linaro Limited. All rights reserved.
      5 *
      6 *  This program and the accompanying materials
      7 *  are licensed and made available under the terms and conditions of the BSD License
      8 *  which accompanies this distribution.  The full text of the license may be found at
      9 *  http://opensource.org/licenses/bsd-license.php
     10 *
     11 *  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 *  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 *
     14 **/
     15 
     16 #include <Uefi/UefiBaseType.h>
     17 #include <Uefi/UefiSpec.h>
     18 #include <Library/DebugLib.h>
     19 #include <Library/EfiTimeBaseLib.h>
     20 
     21 // Define EPOCH (1970-JANUARY-01) in the Julian Date representation
     22 #define EPOCH_JULIAN_DATE                               2440588
     23 
     24 BOOLEAN
     25 EFIAPI
     26 IsLeapYear (
     27   IN EFI_TIME *Time
     28   )
     29 {
     30   if (Time->Year % 4 == 0) {
     31     if (Time->Year % 100 == 0) {
     32       if (Time->Year % 400 == 0) {
     33         return TRUE;
     34       } else {
     35         return FALSE;
     36       }
     37     } else {
     38       return TRUE;
     39     }
     40   } else {
     41     return FALSE;
     42   }
     43 }
     44 
     45 BOOLEAN
     46 EFIAPI
     47 IsDayValid (
     48   IN EFI_TIME *Time
     49   )
     50 {
     51   INTN DayOfMonth[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
     52 
     53   if (Time->Day < 1 ||
     54       Time->Day > DayOfMonth[Time->Month - 1] ||
     55       (Time->Month == 2 && (!IsLeapYear (Time) && Time->Day > 28))
     56      ) {
     57     return FALSE;
     58   }
     59 
     60   return TRUE;
     61 }
     62 
     63 BOOLEAN
     64 EFIAPI
     65 IsTimeValid(
     66   IN EFI_TIME *Time
     67   )
     68 {
     69   // Check the input parameters are within the range specified by UEFI
     70   if ((Time->Year   < 2000) ||
     71      (Time->Year   > 2099) ||
     72      (Time->Month  < 1   ) ||
     73      (Time->Month  > 12  ) ||
     74      (!IsDayValid (Time)    ) ||
     75      (Time->Hour   > 23  ) ||
     76      (Time->Minute > 59  ) ||
     77      (Time->Second > 59  ) ||
     78      (Time->Nanosecond > 999999999) ||
     79      (!((Time->TimeZone == EFI_UNSPECIFIED_TIMEZONE) || ((Time->TimeZone >= -1440) && (Time->TimeZone <= 1440)))) ||
     80      (Time->Daylight & (~(EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT)))
     81   ) {
     82     return FALSE;
     83   }
     84 
     85   return TRUE;
     86 }
     87 
     88 /**
     89   Converts Epoch seconds (elapsed since 1970 JANUARY 01, 00:00:00 UTC) to EFI_TIME
     90  **/
     91 VOID
     92 EpochToEfiTime (
     93   IN  UINTN     EpochSeconds,
     94   OUT EFI_TIME  *Time
     95   )
     96 {
     97   UINTN         a;
     98   UINTN         b;
     99   UINTN         c;
    100   UINTN         d;
    101   UINTN         g;
    102   UINTN         j;
    103   UINTN         m;
    104   UINTN         y;
    105   UINTN         da;
    106   UINTN         db;
    107   UINTN         dc;
    108   UINTN         dg;
    109   UINTN         hh;
    110   UINTN         mm;
    111   UINTN         ss;
    112   UINTN         J;
    113 
    114   J  = (EpochSeconds / 86400) + 2440588;
    115   j  = J + 32044;
    116   g  = j / 146097;
    117   dg = j % 146097;
    118   c  = (((dg / 36524) + 1) * 3) / 4;
    119   dc = dg - (c * 36524);
    120   b  = dc / 1461;
    121   db = dc % 1461;
    122   a  = (((db / 365) + 1) * 3) / 4;
    123   da = db - (a * 365);
    124   y  = (g * 400) + (c * 100) + (b * 4) + a;
    125   m  = (((da * 5) + 308) / 153) - 2;
    126   d  = da - (((m + 4) * 153) / 5) + 122;
    127 
    128   Time->Year  = y - 4800 + ((m + 2) / 12);
    129   Time->Month = ((m + 2) % 12) + 1;
    130   Time->Day   = d + 1;
    131 
    132   ss = EpochSeconds % 60;
    133   a  = (EpochSeconds - ss) / 60;
    134   mm = a % 60;
    135   b = (a - mm) / 60;
    136   hh = b % 24;
    137 
    138   Time->Hour        = hh;
    139   Time->Minute      = mm;
    140   Time->Second      = ss;
    141   Time->Nanosecond  = 0;
    142 
    143 }
    144 
    145 /**
    146   Converts EFI_TIME to Epoch seconds (elapsed since 1970 JANUARY 01, 00:00:00 UTC)
    147  **/
    148 UINTN
    149 EfiTimeToEpoch (
    150   IN  EFI_TIME  *Time
    151   )
    152 {
    153   UINTN a;
    154   UINTN y;
    155   UINTN m;
    156   UINTN JulianDate;  // Absolute Julian Date representation of the supplied Time
    157   UINTN EpochDays;   // Number of days elapsed since EPOCH_JULIAN_DAY
    158   UINTN EpochSeconds;
    159 
    160   a = (14 - Time->Month) / 12 ;
    161   y = Time->Year + 4800 - a;
    162   m = Time->Month + (12*a) - 3;
    163 
    164   JulianDate = Time->Day + ((153*m + 2)/5) + (365*y) + (y/4) - (y/100) + (y/400) - 32045;
    165 
    166   ASSERT (JulianDate >= EPOCH_JULIAN_DATE);
    167   EpochDays = JulianDate - EPOCH_JULIAN_DATE;
    168 
    169   EpochSeconds = (EpochDays * SEC_PER_DAY) + ((UINTN)Time->Hour * SEC_PER_HOUR) + (Time->Minute * SEC_PER_MIN) + Time->Second;
    170 
    171   return EpochSeconds;
    172 }
    173