/** @file * * Copyright (c) 2016, Hisilicon Limited. All rights reserved. * Copyright (c) 2016-2019, Linaro Limited. All rights reserved. * Copyright (c) 2021, Ampere Computing LLC. All rights reserved. * * SPDX-License-Identifier: BSD-2-Clause-Patent * **/ #include #include #include #include /** Converts Epoch seconds (elapsed since 1970 JANUARY 01, 00:00:00 UTC) to EFI_TIME. @param EpochSeconds Epoch seconds. @param Time The time converted to UEFI format. **/ VOID EFIAPI EpochToEfiTime ( IN UINTN EpochSeconds, OUT EFI_TIME *Time ) { UINTN a; UINTN b; UINTN c; UINTN d; UINTN g; UINTN j; UINTN m; UINTN y; UINTN da; UINTN db; UINTN dc; UINTN dg; UINTN hh; UINTN mm; UINTN ss; UINTN J; J = (EpochSeconds / 86400) + 2440588; j = J + 32044; g = j / 146097; dg = j % 146097; c = (((dg / 36524) + 1) * 3) / 4; dc = dg - (c * 36524); b = dc / 1461; db = dc % 1461; a = (((db / 365) + 1) * 3) / 4; da = db - (a * 365); y = (g * 400) + (c * 100) + (b * 4) + a; m = (((da * 5) + 308) / 153) - 2; d = da - (((m + 4) * 153) / 5) + 122; Time->Year = (UINT16)(y - 4800 + ((m + 2) / 12)); Time->Month = ((m + 2) % 12) + 1; Time->Day = (UINT8)(d + 1); ss = EpochSeconds % 60; a = (EpochSeconds - ss) / 60; mm = a % 60; b = (a - mm) / 60; hh = b % 24; Time->Hour = (UINT8)hh; Time->Minute = (UINT8)mm; Time->Second = (UINT8)ss; Time->Nanosecond = 0; } /** Calculate Epoch days. @param Time The UEFI time to be calculated. @return Number of days. **/ UINTN EFIAPI EfiGetEpochDays ( IN EFI_TIME *Time ) { UINTN a; UINTN y; UINTN m; UINTN JulianDate; // Absolute Julian Date representation of the supplied Time UINTN EpochDays; // Number of days elapsed since EPOCH_JULIAN_DAY a = (14 - Time->Month) / 12; y = Time->Year + 4800 - a; m = Time->Month + (12*a) - 3; JulianDate = Time->Day + ((153*m + 2)/5) + (365*y) + (y/4) - (y/100) + (y/400) - 32045; ASSERT (JulianDate >= EPOCH_JULIAN_DATE); EpochDays = JulianDate - EPOCH_JULIAN_DATE; return EpochDays; } /** Converts EFI_TIME to Epoch seconds (elapsed since 1970 JANUARY 01, 00:00:00 UTC). @param Time The UEFI time to be converted. @return Number of seconds. **/ UINTN EFIAPI EfiTimeToEpoch ( IN EFI_TIME *Time ) { UINTN EpochDays; // Number of days elapsed since EPOCH_JULIAN_DAY UINTN EpochSeconds; EpochDays = EfiGetEpochDays (Time); EpochSeconds = (EpochDays * SEC_PER_DAY) + ((UINTN)Time->Hour * SEC_PER_HOUR) + (Time->Minute * SEC_PER_MIN) + Time->Second; return EpochSeconds; } /** Get the day of the week from the UEFI time. @param Time The UEFI time to be calculated. @return The day of the week: Sunday=0, Monday=1, ... Saturday=6 **/ UINTN EfiTimeToWday ( IN EFI_TIME *Time ) { UINTN EpochDays; // Number of days elapsed since EPOCH_JULIAN_DAY EpochDays = EfiGetEpochDays (Time); // 4=1/1/1970 was a Thursday return (EpochDays + 4) % 7; } /** Check if it is a leap year. @param Time The UEFI time to be checked. @retval TRUE It is a leap year. @retval FALSE It is NOT a leap year. **/ BOOLEAN EFIAPI IsLeapYear ( IN EFI_TIME *Time ) { if (Time->Year % 4 == 0) { if (Time->Year % 100 == 0) { if (Time->Year % 400 == 0) { return TRUE; } else { return FALSE; } } else { return TRUE; } } else { return FALSE; } } /** Check if the day in the UEFI time is valid. @param Time The UEFI time to be checked. @retval TRUE Valid. @retval FALSE Invalid. **/ BOOLEAN EFIAPI IsDayValid ( IN EFI_TIME *Time ) { STATIC CONST INTN DayOfMonth[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; if ((Time->Day < 1) || (Time->Day > DayOfMonth[Time->Month - 1]) || ((Time->Month == 2) && (!IsLeapYear (Time) && (Time->Day > 28))) ) { return FALSE; } return TRUE; } /** Check if the time zone is valid. Valid values are between -1440 and 1440 or 2047 (EFI_UNSPECIFIED_TIMEZONE). @param TimeZone The time zone to be checked. @retval TRUE Valid. @retval FALSE Invalid. **/ BOOLEAN EFIAPI IsValidTimeZone ( IN INT16 TimeZone ) { return TimeZone == EFI_UNSPECIFIED_TIMEZONE || (TimeZone >= -1440 && TimeZone <= 1440); } /** Check if the daylight is valid. Valid values are: 0 : Time is not affected. 1 : Time is affected, and has not been adjusted for daylight savings. 3 : Time is affected, and has been adjusted for daylight savings. All other values are invalid. @param Daylight The daylight to be checked. @retval TRUE Valid. @retval FALSE Invalid. **/ BOOLEAN EFIAPI IsValidDaylight ( IN INT8 Daylight ) { return Daylight == 0 || Daylight == EFI_TIME_ADJUST_DAYLIGHT || Daylight == (EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT); } /** Check if the UEFI time is valid. @param Time The UEFI time to be checked. @retval TRUE Valid. @retval FALSE Invalid. **/ BOOLEAN EFIAPI IsTimeValid ( IN EFI_TIME *Time ) { // Check the input parameters are within the range specified by UEFI if ((Time->Year < 2000) || (Time->Year > 2099) || (Time->Month < 1) || (Time->Month > 12) || (!IsDayValid (Time)) || (Time->Hour > 23) || (Time->Minute > 59) || (Time->Second > 59) || (Time->Nanosecond > 999999999) || (!IsValidTimeZone (Time->TimeZone)) || (!IsValidDaylight (Time->Daylight))) { return FALSE; } return TRUE; }