1 /** @file
2 *
3 *  Copyright (c) 2016, Hisilicon Limited. All rights reserved.
4 *  Copyright (c) 2016-2019, Linaro Limited. All rights reserved.
5 *
6 *  SPDX-License-Identifier: BSD-2-Clause-Patent
7 *
8 **/
9 
10 #include <Uefi/UefiBaseType.h>
11 #include <Uefi/UefiSpec.h>
12 #include <Library/DebugLib.h>
13 #include <Library/TimeBaseLib.h>
14 
15 /**
16   Converts Epoch seconds (elapsed since 1970 JANUARY 01, 00:00:00 UTC) to EFI_TIME
17  **/
18 VOID
19 EFIAPI
EpochToEfiTime(IN UINTN EpochSeconds,OUT EFI_TIME * Time)20 EpochToEfiTime (
21   IN  UINTN     EpochSeconds,
22   OUT EFI_TIME  *Time
23   )
24 {
25   UINTN         a;
26   UINTN         b;
27   UINTN         c;
28   UINTN         d;
29   UINTN         g;
30   UINTN         j;
31   UINTN         m;
32   UINTN         y;
33   UINTN         da;
34   UINTN         db;
35   UINTN         dc;
36   UINTN         dg;
37   UINTN         hh;
38   UINTN         mm;
39   UINTN         ss;
40   UINTN         J;
41 
42   J  = (EpochSeconds / 86400) + 2440588;
43   j  = J + 32044;
44   g  = j / 146097;
45   dg = j % 146097;
46   c  = (((dg / 36524) + 1) * 3) / 4;
47   dc = dg - (c * 36524);
48   b  = dc / 1461;
49   db = dc % 1461;
50   a  = (((db / 365) + 1) * 3) / 4;
51   da = db - (a * 365);
52   y  = (g * 400) + (c * 100) + (b * 4) + a;
53   m  = (((da * 5) + 308) / 153) - 2;
54   d  = da - (((m + 4) * 153) / 5) + 122;
55 
56   Time->Year  = (UINT16)(y - 4800 + ((m + 2) / 12));
57   Time->Month = ((m + 2) % 12) + 1;
58   Time->Day   = (UINT8)(d + 1);
59 
60   ss = EpochSeconds % 60;
61   a  = (EpochSeconds - ss) / 60;
62   mm = a % 60;
63   b = (a - mm) / 60;
64   hh = b % 24;
65 
66   Time->Hour        = (UINT8)hh;
67   Time->Minute      = (UINT8)mm;
68   Time->Second      = (UINT8)ss;
69   Time->Nanosecond  = 0;
70 
71 }
72 
73 /**
74   Calculate Epoch days
75  **/
76 UINTN
77 EFIAPI
EfiGetEpochDays(IN EFI_TIME * Time)78 EfiGetEpochDays (
79   IN  EFI_TIME  *Time
80   )
81 {
82   UINTN a;
83   UINTN y;
84   UINTN m;
85   UINTN JulianDate;  // Absolute Julian Date representation of the supplied Time
86   UINTN EpochDays;   // Number of days elapsed since EPOCH_JULIAN_DAY
87 
88   a = (14 - Time->Month) / 12 ;
89   y = Time->Year + 4800 - a;
90   m = Time->Month + (12*a) - 3;
91 
92   JulianDate = Time->Day + ((153*m + 2)/5) + (365*y) + (y/4) - (y/100) + (y/400) - 32045;
93 
94   ASSERT (JulianDate >= EPOCH_JULIAN_DATE);
95   EpochDays = JulianDate - EPOCH_JULIAN_DATE;
96 
97   return EpochDays;
98 }
99 /**
100   Converts EFI_TIME to Epoch seconds (elapsed since 1970 JANUARY 01, 00:00:00 UTC)
101  **/
102 UINT32
103 EFIAPI
EfiTimeToEpoch(IN EFI_TIME * Time)104 EfiTimeToEpoch (
105   IN  EFI_TIME  *Time
106   )
107 {
108   UINT32 EpochDays;   // Number of days elapsed since EPOCH_JULIAN_DAY
109   UINT32 EpochSeconds;
110 
111   EpochDays = EfiGetEpochDays (Time);
112 
113   EpochSeconds = (EpochDays * SEC_PER_DAY) + ((UINTN)Time->Hour * SEC_PER_HOUR) + (Time->Minute * SEC_PER_MIN) + Time->Second;
114 
115   return EpochSeconds;
116 }
117 
118 /**
119   returns Day of the week [0-6] 0=Sunday
120  **/
121 UINTN
EfiTimeToWday(IN EFI_TIME * Time)122 EfiTimeToWday (
123   IN  EFI_TIME  *Time
124   )
125 {
126   UINTN EpochDays;   // Number of days elapsed since EPOCH_JULIAN_DAY
127 
128   EpochDays = EfiGetEpochDays (Time);
129 
130   // 4=1/1/1970 was a Thursday
131 
132   return (EpochDays + 4) % 7;
133 }
134 
135 BOOLEAN
136 EFIAPI
IsLeapYear(IN EFI_TIME * Time)137 IsLeapYear (
138   IN EFI_TIME   *Time
139   )
140 {
141   if (Time->Year % 4 == 0) {
142     if (Time->Year % 100 == 0) {
143       if (Time->Year % 400 == 0) {
144         return TRUE;
145       } else {
146         return FALSE;
147       }
148     } else {
149       return TRUE;
150     }
151   } else {
152     return FALSE;
153   }
154 }
155 
156 BOOLEAN
157 EFIAPI
IsDayValid(IN EFI_TIME * Time)158 IsDayValid (
159   IN  EFI_TIME  *Time
160   )
161 {
162   STATIC CONST INTN DayOfMonth[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
163 
164   if (Time->Day < 1 ||
165       Time->Day > DayOfMonth[Time->Month - 1] ||
166       (Time->Month == 2 && (!IsLeapYear (Time) && Time->Day > 28))
167      ) {
168     return FALSE;
169   }
170 
171   return TRUE;
172 }
173 
174 BOOLEAN
175 EFIAPI
IsTimeValid(IN EFI_TIME * Time)176 IsTimeValid(
177   IN EFI_TIME *Time
178   )
179 {
180   // Check the input parameters are within the range specified by UEFI
181   if ((Time->Year   < 2000) ||
182      (Time->Year   > 2099) ||
183      (Time->Month  < 1   ) ||
184      (Time->Month  > 12  ) ||
185      (!IsDayValid (Time)    ) ||
186      (Time->Hour   > 23  ) ||
187      (Time->Minute > 59  ) ||
188      (Time->Second > 59  ) ||
189      (Time->Nanosecond > 999999999) ||
190      (!((Time->TimeZone == EFI_UNSPECIFIED_TIMEZONE) || ((Time->TimeZone >= -1440) && (Time->TimeZone <= 1440)))) ||
191      (Time->Daylight & (~(EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT)))
192   ) {
193     return FALSE;
194   }
195 
196   return TRUE;
197 }
198