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
IsLeapYear(IN EFI_TIME * Time)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
IsDayValid(IN EFI_TIME * Time)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
IsTimeValid(IN EFI_TIME * Time)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
EpochToEfiTime(IN UINTN EpochSeconds,OUT EFI_TIME * Time)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
EfiTimeToEpoch(IN EFI_TIME * Time)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