You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-17 14:11:06 +00:00
Merge pull request #49123 from aaronfranke/it-is-time
Add a Time singleton
This commit is contained in:
@@ -42,28 +42,6 @@
|
||||
#include "core/os/keyboard.h"
|
||||
#include "core/os/os.h"
|
||||
|
||||
/**
|
||||
* Time constants borrowed from loc_time.h
|
||||
*/
|
||||
#define EPOCH_YR 1970 /* EPOCH = Jan 1 1970 00:00:00 */
|
||||
#define SECS_DAY (24L * 60L * 60L)
|
||||
#define LEAPYEAR(year) (!((year) % 4) && (((year) % 100) || !((year) % 400)))
|
||||
#define YEARSIZE(year) (LEAPYEAR(year) ? 366 : 365)
|
||||
#define SECOND_KEY "second"
|
||||
#define MINUTE_KEY "minute"
|
||||
#define HOUR_KEY "hour"
|
||||
#define DAY_KEY "day"
|
||||
#define MONTH_KEY "month"
|
||||
#define YEAR_KEY "year"
|
||||
#define WEEKDAY_KEY "weekday"
|
||||
#define DST_KEY "dst"
|
||||
|
||||
/// Table of number of days in each month (for regular year and leap year)
|
||||
static const unsigned int MONTH_DAYS_TABLE[2][12] = {
|
||||
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
|
||||
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
|
||||
};
|
||||
|
||||
////// _ResourceLoader //////
|
||||
|
||||
_ResourceLoader *_ResourceLoader::singleton = nullptr;
|
||||
@@ -322,197 +300,6 @@ uint64_t _OS::get_static_memory_peak_usage() const {
|
||||
return OS::get_singleton()->get_static_memory_peak_usage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current datetime with consideration for utc and
|
||||
* dst
|
||||
*/
|
||||
Dictionary _OS::get_datetime(bool utc) const {
|
||||
Dictionary dated = get_date(utc);
|
||||
Dictionary timed = get_time(utc);
|
||||
|
||||
List<Variant> keys;
|
||||
timed.get_key_list(&keys);
|
||||
|
||||
for (int i = 0; i < keys.size(); i++) {
|
||||
dated[keys[i]] = timed[keys[i]];
|
||||
}
|
||||
|
||||
return dated;
|
||||
}
|
||||
|
||||
Dictionary _OS::get_date(bool utc) const {
|
||||
OS::Date date = OS::get_singleton()->get_date(utc);
|
||||
Dictionary dated;
|
||||
dated[YEAR_KEY] = date.year;
|
||||
dated[MONTH_KEY] = date.month;
|
||||
dated[DAY_KEY] = date.day;
|
||||
dated[WEEKDAY_KEY] = date.weekday;
|
||||
dated[DST_KEY] = date.dst;
|
||||
return dated;
|
||||
}
|
||||
|
||||
Dictionary _OS::get_time(bool utc) const {
|
||||
OS::Time time = OS::get_singleton()->get_time(utc);
|
||||
Dictionary timed;
|
||||
timed[HOUR_KEY] = time.hour;
|
||||
timed[MINUTE_KEY] = time.min;
|
||||
timed[SECOND_KEY] = time.sec;
|
||||
return timed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an epoch time value from a dictionary of time values
|
||||
* @p datetime must be populated with the following keys:
|
||||
* day, hour, minute, month, second, year. (dst is ignored).
|
||||
*
|
||||
* You can pass the output from
|
||||
* get_datetime_from_unix_time directly into this function
|
||||
*
|
||||
* @param datetime dictionary of date and time values to convert
|
||||
*
|
||||
* @return epoch calculated
|
||||
*/
|
||||
int64_t _OS::get_unix_time_from_datetime(Dictionary datetime) const {
|
||||
// if datetime is an empty Dictionary throws an error
|
||||
ERR_FAIL_COND_V_MSG(datetime.is_empty(), 0, "Invalid datetime Dictionary: Dictionary is empty");
|
||||
|
||||
// Bunch of conversion constants
|
||||
static const unsigned int SECONDS_PER_MINUTE = 60;
|
||||
static const unsigned int MINUTES_PER_HOUR = 60;
|
||||
static const unsigned int HOURS_PER_DAY = 24;
|
||||
static const unsigned int SECONDS_PER_HOUR = MINUTES_PER_HOUR * SECONDS_PER_MINUTE;
|
||||
static const unsigned int SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY;
|
||||
|
||||
// Get all time values from the dictionary, set to zero if it doesn't exist.
|
||||
// Risk incorrect calculation over throwing errors
|
||||
unsigned int second = ((datetime.has(SECOND_KEY)) ? static_cast<unsigned int>(datetime[SECOND_KEY]) : 0);
|
||||
unsigned int minute = ((datetime.has(MINUTE_KEY)) ? static_cast<unsigned int>(datetime[MINUTE_KEY]) : 0);
|
||||
unsigned int hour = ((datetime.has(HOUR_KEY)) ? static_cast<unsigned int>(datetime[HOUR_KEY]) : 0);
|
||||
unsigned int day = ((datetime.has(DAY_KEY)) ? static_cast<unsigned int>(datetime[DAY_KEY]) : 1);
|
||||
unsigned int month = ((datetime.has(MONTH_KEY)) ? static_cast<unsigned int>(datetime[MONTH_KEY]) : 1);
|
||||
unsigned int year = ((datetime.has(YEAR_KEY)) ? static_cast<unsigned int>(datetime[YEAR_KEY]) : 1970);
|
||||
|
||||
/// How many days come before each month (0-12)
|
||||
static const unsigned short int DAYS_PAST_THIS_YEAR_TABLE[2][13] = {
|
||||
/* Normal years. */
|
||||
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
|
||||
/* Leap years. */
|
||||
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
|
||||
};
|
||||
|
||||
ERR_FAIL_COND_V_MSG(second > 59, 0, "Invalid second value of: " + itos(second) + ".");
|
||||
ERR_FAIL_COND_V_MSG(minute > 59, 0, "Invalid minute value of: " + itos(minute) + ".");
|
||||
ERR_FAIL_COND_V_MSG(hour > 23, 0, "Invalid hour value of: " + itos(hour) + ".");
|
||||
ERR_FAIL_COND_V_MSG(year == 0, 0, "Years before 1 AD are not supported. Value passed: " + itos(year) + ".");
|
||||
ERR_FAIL_COND_V_MSG(month > 12 || month == 0, 0, "Invalid month value of: " + itos(month) + ".");
|
||||
// Do this check after month is tested as valid
|
||||
unsigned int days_in_month = MONTH_DAYS_TABLE[LEAPYEAR(year)][month - 1];
|
||||
ERR_FAIL_COND_V_MSG(day == 0 || day > days_in_month, 0, "Invalid day value of: " + itos(day) + ". It should be comprised between 1 and " + itos(days_in_month) + " for month " + itos(month) + ".");
|
||||
|
||||
// Calculate all the seconds from months past in this year
|
||||
uint64_t SECONDS_FROM_MONTHS_PAST_THIS_YEAR = DAYS_PAST_THIS_YEAR_TABLE[LEAPYEAR(year)][month - 1] * SECONDS_PER_DAY;
|
||||
|
||||
int64_t SECONDS_FROM_YEARS_PAST = 0;
|
||||
if (year >= EPOCH_YR) {
|
||||
for (unsigned int iyear = EPOCH_YR; iyear < year; iyear++) {
|
||||
SECONDS_FROM_YEARS_PAST += YEARSIZE(iyear) * SECONDS_PER_DAY;
|
||||
}
|
||||
} else {
|
||||
for (unsigned int iyear = EPOCH_YR - 1; iyear >= year; iyear--) {
|
||||
SECONDS_FROM_YEARS_PAST -= YEARSIZE(iyear) * SECONDS_PER_DAY;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t epoch =
|
||||
second +
|
||||
minute * SECONDS_PER_MINUTE +
|
||||
hour * SECONDS_PER_HOUR +
|
||||
// Subtract 1 from day, since the current day isn't over yet
|
||||
// and we cannot count all 24 hours.
|
||||
(day - 1) * SECONDS_PER_DAY +
|
||||
SECONDS_FROM_MONTHS_PAST_THIS_YEAR +
|
||||
SECONDS_FROM_YEARS_PAST;
|
||||
return epoch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a dictionary of time values when given epoch time
|
||||
*
|
||||
* Dictionary Time values will be a union if values from #get_time
|
||||
* and #get_date dictionaries (with the exception of dst =
|
||||
* day light standard time, as it cannot be determined from epoch)
|
||||
*
|
||||
* @param unix_time_val epoch time to convert
|
||||
*
|
||||
* @return dictionary of date and time values
|
||||
*/
|
||||
Dictionary _OS::get_datetime_from_unix_time(int64_t unix_time_val) const {
|
||||
OS::Date date;
|
||||
OS::Time time;
|
||||
|
||||
long dayclock, dayno;
|
||||
int year = EPOCH_YR;
|
||||
|
||||
if (unix_time_val >= 0) {
|
||||
dayno = unix_time_val / SECS_DAY;
|
||||
dayclock = unix_time_val % SECS_DAY;
|
||||
/* day 0 was a thursday */
|
||||
date.weekday = static_cast<OS::Weekday>((dayno + 4) % 7);
|
||||
while (dayno >= YEARSIZE(year)) {
|
||||
dayno -= YEARSIZE(year);
|
||||
year++;
|
||||
}
|
||||
} else {
|
||||
dayno = (unix_time_val - SECS_DAY + 1) / SECS_DAY;
|
||||
dayclock = unix_time_val - dayno * SECS_DAY;
|
||||
date.weekday = static_cast<OS::Weekday>(((dayno % 7) + 11) % 7);
|
||||
do {
|
||||
year--;
|
||||
dayno += YEARSIZE(year);
|
||||
} while (dayno < 0);
|
||||
}
|
||||
|
||||
time.sec = dayclock % 60;
|
||||
time.min = (dayclock % 3600) / 60;
|
||||
time.hour = dayclock / 3600;
|
||||
date.year = year;
|
||||
|
||||
size_t imonth = 0;
|
||||
|
||||
while ((unsigned long)dayno >= MONTH_DAYS_TABLE[LEAPYEAR(year)][imonth]) {
|
||||
dayno -= MONTH_DAYS_TABLE[LEAPYEAR(year)][imonth];
|
||||
imonth++;
|
||||
}
|
||||
|
||||
/// Add 1 to month to make sure months are indexed starting at 1
|
||||
date.month = static_cast<OS::Month>(imonth + 1);
|
||||
|
||||
date.day = dayno + 1;
|
||||
|
||||
Dictionary timed;
|
||||
timed[HOUR_KEY] = time.hour;
|
||||
timed[MINUTE_KEY] = time.min;
|
||||
timed[SECOND_KEY] = time.sec;
|
||||
timed[YEAR_KEY] = date.year;
|
||||
timed[MONTH_KEY] = date.month;
|
||||
timed[DAY_KEY] = date.day;
|
||||
timed[WEEKDAY_KEY] = date.weekday;
|
||||
|
||||
return timed;
|
||||
}
|
||||
|
||||
Dictionary _OS::get_time_zone_info() const {
|
||||
OS::TimeZoneInfo info = OS::get_singleton()->get_time_zone_info();
|
||||
Dictionary infod;
|
||||
infod["bias"] = info.bias;
|
||||
infod["name"] = info.name;
|
||||
return infod;
|
||||
}
|
||||
|
||||
double _OS::get_unix_time() const {
|
||||
return OS::get_singleton()->get_unix_time();
|
||||
}
|
||||
|
||||
/** This method uses a signed argument for better error reporting as it's used from the scripting API. */
|
||||
void _OS::delay_usec(int p_usec) const {
|
||||
ERR_FAIL_COND_MSG(
|
||||
@@ -529,14 +316,6 @@ void _OS::delay_msec(int p_msec) const {
|
||||
OS::get_singleton()->delay_usec(int64_t(p_msec) * 1000);
|
||||
}
|
||||
|
||||
uint32_t _OS::get_ticks_msec() const {
|
||||
return OS::get_singleton()->get_ticks_msec();
|
||||
}
|
||||
|
||||
uint64_t _OS::get_ticks_usec() const {
|
||||
return OS::get_singleton()->get_ticks_usec();
|
||||
}
|
||||
|
||||
bool _OS::can_use_threads() const {
|
||||
return OS::get_singleton()->can_use_threads();
|
||||
}
|
||||
@@ -716,18 +495,8 @@ void _OS::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("get_name"), &_OS::get_name);
|
||||
ClassDB::bind_method(D_METHOD("get_cmdline_args"), &_OS::get_cmdline_args);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_datetime", "utc"), &_OS::get_datetime, DEFVAL(false));
|
||||
ClassDB::bind_method(D_METHOD("get_date", "utc"), &_OS::get_date, DEFVAL(false));
|
||||
ClassDB::bind_method(D_METHOD("get_time", "utc"), &_OS::get_time, DEFVAL(false));
|
||||
ClassDB::bind_method(D_METHOD("get_time_zone_info"), &_OS::get_time_zone_info);
|
||||
ClassDB::bind_method(D_METHOD("get_unix_time"), &_OS::get_unix_time);
|
||||
ClassDB::bind_method(D_METHOD("get_datetime_from_unix_time", "unix_time_val"), &_OS::get_datetime_from_unix_time);
|
||||
ClassDB::bind_method(D_METHOD("get_unix_time_from_datetime", "datetime"), &_OS::get_unix_time_from_datetime);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("delay_usec", "usec"), &_OS::delay_usec);
|
||||
ClassDB::bind_method(D_METHOD("delay_msec", "msec"), &_OS::delay_msec);
|
||||
ClassDB::bind_method(D_METHOD("get_ticks_msec"), &_OS::get_ticks_msec);
|
||||
ClassDB::bind_method(D_METHOD("get_ticks_usec"), &_OS::get_ticks_usec);
|
||||
ClassDB::bind_method(D_METHOD("get_locale"), &_OS::get_locale);
|
||||
ClassDB::bind_method(D_METHOD("get_model_name"), &_OS::get_model_name);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user