Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a Time singleton #49123

Merged
merged 1 commit into from
Jun 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
231 changes: 0 additions & 231 deletions core/core_bind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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(
Expand All @@ -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();
}
Expand Down Expand Up @@ -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);

Expand Down
8 changes: 0 additions & 8 deletions core/core_bind.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,14 +199,6 @@ class _OS : public Object {

void set_use_file_access_save_and_swap(bool p_enable);

Dictionary get_date(bool utc) const;
Dictionary get_time(bool utc) const;
Dictionary get_datetime(bool utc) const;
Dictionary get_datetime_from_unix_time(int64_t unix_time_val) const;
int64_t get_unix_time_from_datetime(Dictionary datetime) const;
Dictionary get_time_zone_info() const;
double get_unix_time() const;

uint64_t get_static_memory_usage() const;
uint64_t get_static_memory_peak_usage() const;

Expand Down
7 changes: 2 additions & 5 deletions core/io/logger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "core/config/project_settings.h"
#include "core/os/dir_access.h"
#include "core/os/os.h"
#include "core/os/time.h"
#include "core/string/print_string.h"

#if defined(MINGW_ENABLED) || defined(_MSC_VER)
Expand Down Expand Up @@ -156,11 +157,7 @@ void RotatedFileLogger::rotate_file() {

if (FileAccess::exists(base_path)) {
if (max_files > 1) {
char timestamp[21];
OS::Date date = OS::get_singleton()->get_date();
OS::Time time = OS::get_singleton()->get_time();
sprintf(timestamp, "_%04d-%02d-%02d_%02d.%02d.%02d", date.year, date.month, date.day, time.hour, time.min, time.sec);

String timestamp = Time::get_singleton()->get_datetime_string_from_system().replace(":", ".");
String backup_name = base_path.get_basename() + timestamp;
if (base_path.get_extension() != String()) {
backup_name += "." + base_path.get_extension();
Expand Down
33 changes: 2 additions & 31 deletions core/os/os.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,37 +47,8 @@ OS *OS::get_singleton() {
return singleton;
}

uint32_t OS::get_ticks_msec() const {
return get_ticks_usec() / 1000;
}

String OS::get_iso_date_time(bool local) const {
OS::Date date = get_date(local);
OS::Time time = get_time(local);

String timezone;
if (!local) {
TimeZoneInfo zone = get_time_zone_info();
if (zone.bias >= 0) {
timezone = "+";
}
timezone = timezone + itos(zone.bias / 60).pad_zeros(2) + itos(zone.bias % 60).pad_zeros(2);
} else {
timezone = "Z";
}

return itos(date.year).pad_zeros(2) +
"-" +
itos(date.month).pad_zeros(2) +
"-" +
itos(date.day).pad_zeros(2) +
"T" +
itos(time.hour).pad_zeros(2) +
":" +
itos(time.min).pad_zeros(2) +
":" +
itos(time.sec).pad_zeros(2) +
timezone;
uint64_t OS::get_ticks_msec() const {
return get_ticks_usec() / 1000ULL;
}

double OS::get_unix_time() const {
Expand Down
Loading