mirror of
https://gitlab.com/bztsrc/posix-uefi.git
synced 2024-12-29 05:55:31 +01:00
146 lines
4.1 KiB
C
146 lines
4.1 KiB
C
/*
|
|
* time.c
|
|
*
|
|
* Copyright (C) 2021 bzt (bztsrc@gitlab)
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person
|
|
* obtaining a copy of this software and associated documentation
|
|
* files (the "Software"), to deal in the Software without
|
|
* restriction, including without limitation the rights to use, copy,
|
|
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
* of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be
|
|
* included in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
*
|
|
* This file is part of the POSIX-UEFI package.
|
|
* @brief Implementing functions which are defined in time.h
|
|
*
|
|
*/
|
|
|
|
#include <uefi.h>
|
|
|
|
static struct tm __tm;
|
|
time_t __mktime_efi(efi_time_t *t);
|
|
|
|
/* from musl */
|
|
static uint64_t __year_to_secs(uint64_t year, int *is_leap)
|
|
{
|
|
int y, cycles, centuries, leaps, rem;
|
|
|
|
if (year-2ULL <= 136) {
|
|
y = (int)year;
|
|
leaps = (y-68)>>2;
|
|
if (!((y-68)&3)) {
|
|
leaps--;
|
|
if (is_leap) *is_leap = 1;
|
|
} else if (is_leap) *is_leap = 0;
|
|
return 31536000ULL*(uint64_t)(y-70) + 86400ULL*(uint64_t)leaps;
|
|
}
|
|
|
|
if (!is_leap) is_leap = &(int){0};
|
|
cycles = (int)((year-100) / 400);
|
|
rem = (year-100) % 400;
|
|
if (rem < 0) {
|
|
cycles--;
|
|
rem += 400;
|
|
}
|
|
if (!rem) {
|
|
*is_leap = 1;
|
|
centuries = 0;
|
|
leaps = 0;
|
|
} else {
|
|
if (rem >= 200) {
|
|
if (rem >= 300) { centuries = 3; rem -= 300; }
|
|
else { centuries = 2; rem -= 200; }
|
|
} else {
|
|
if (rem >= 100) { centuries = 1; rem -= 100; }
|
|
else centuries = 0;
|
|
}
|
|
if (!rem) {
|
|
*is_leap = 0;
|
|
leaps = 0;
|
|
} else {
|
|
leaps = rem / 4;
|
|
rem %= 4;
|
|
*is_leap = !rem;
|
|
}
|
|
}
|
|
|
|
leaps += 97*cycles + 24*centuries - *is_leap;
|
|
|
|
return (uint64_t)(year-100) * 31536000ULL + (uint64_t)leaps * 86400ULL + 946684800ULL + 86400ULL;
|
|
}
|
|
|
|
time_t __mktime_efi(efi_time_t *t)
|
|
{
|
|
__tm.tm_year = t->Year + (/* workaround some buggy firmware*/ t->Year > 2000 ? -1900 : 98);
|
|
__tm.tm_mon = t->Month - 1;
|
|
__tm.tm_mday = t->Day;
|
|
__tm.tm_hour = t->Hour;
|
|
__tm.tm_min = t->Minute;
|
|
__tm.tm_sec = t->Second;
|
|
__tm.tm_isdst = t->Daylight;
|
|
return mktime(&__tm);
|
|
}
|
|
|
|
/**
|
|
* This isn't POSIX, no arguments. Just returns the current time in struct tm
|
|
*/
|
|
struct tm *localtime (const time_t *__timer)
|
|
{
|
|
efi_time_t t = {0};
|
|
(void)__timer;
|
|
ST->RuntimeServices->GetTime(&t, NULL);
|
|
__mktime_efi(&t);
|
|
return &__tm;
|
|
}
|
|
|
|
time_t mktime(const struct tm *tm)
|
|
{
|
|
static const uint64_t secs_through_month[] = {
|
|
0, 31*86400, 59*86400, 90*86400,
|
|
120*86400, 151*86400, 181*86400, 212*86400,
|
|
243*86400, 273*86400, 304*86400, 334*86400 };
|
|
int is_leap;
|
|
uint64_t year = (uint64_t)tm->tm_year, t, adj;
|
|
int month = tm->tm_mon;
|
|
if (month >= 12 || month < 0) {
|
|
adj = (uint64_t)month / 12;
|
|
month %= 12;
|
|
if (month < 0) {
|
|
adj--;
|
|
month += 12;
|
|
}
|
|
year += adj;
|
|
}
|
|
t = __year_to_secs(year, &is_leap);
|
|
t += secs_through_month[month];
|
|
if (is_leap && month >= 2) t += 86400;
|
|
t += 86400ULL * (uint64_t)(tm->tm_mday-1);
|
|
t += 3600ULL * (uint64_t)tm->tm_hour;
|
|
t += 60ULL * (uint64_t)tm->tm_min;
|
|
t += (uint64_t)tm->tm_sec;
|
|
return (time_t)t;
|
|
}
|
|
|
|
time_t time(time_t *__timer)
|
|
{
|
|
time_t ret;
|
|
efi_time_t t = {0};
|
|
ST->RuntimeServices->GetTime(&t, NULL);
|
|
ret = __mktime_efi(&t);
|
|
if(__timer) *__timer = ret;
|
|
return ret;
|
|
}
|
|
|