diff --git a/core/os/os.cpp b/core/os/os.cpp index 12990c1ce..550efc123 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -86,6 +86,125 @@ uint64_t OS::get_system_time_secs() const { uint64_t OS::get_system_time_msecs() const { return 0; } + +/** + * 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) + +/// 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 } +}; + +OS::DateTime OS::get_datetime_from_unix_time(int64_t unix_time_val) const { + DateTime dt; + + 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 */ + dt.date.weekday = static_cast((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; + dt.date.weekday = static_cast(((dayno % 7) + 11) % 7); + do { + year--; + dayno += YEARSIZE(year); + } while (dayno < 0); + } + + dt.time.sec = dayclock % 60; + dt.time.min = (dayclock % 3600) / 60; + dt.time.hour = dayclock / 3600; + dt.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 + dt.date.month = static_cast(imonth + 1); + + dt.date.day = dayno + 1; + + return dt; +} + +int64_t OS::get_unix_time_from_datetime(const DateTime &datetime) const { + // 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; + + unsigned int second = static_cast(datetime.time.sec); + unsigned int minute = static_cast(datetime.time.min); + unsigned int hour = static_cast(datetime.time.hour); + unsigned int day = static_cast(datetime.date.day); + unsigned int month = static_cast(datetime.date.month); + unsigned int year = static_cast(datetime.date.year); + + /// 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; +} + void OS::debug_break(){ // something diff --git a/core/os/os.h b/core/os/os.h index 038ea0715..8cc043107 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -307,10 +307,14 @@ public: // each time a frame is redrawn as a result of moving the mouse, clicking etc. // This enables us to keep e.g. particle systems processing, but ONLY when other // events have caused a redraw. - virtual bool is_update_pending(bool p_include_redraws = false) const { return !_update_vital_only || (_update_pending && p_include_redraws); } + virtual bool is_update_pending(bool p_include_redraws = false) const { + return !_update_vital_only || (_update_pending && p_include_redraws); + } #else // Always update when outside the editor, UPDATE_VITAL_ONLY has no effect outside the editor. - virtual bool is_update_pending(bool p_include_redraws = false) const { return true; } + virtual bool is_update_pending(bool p_include_redraws = false) const { + return true; + } #endif virtual String get_executable_path() const; @@ -327,7 +331,9 @@ public: virtual bool set_environment(const String &p_var, const String &p_value) const = 0; virtual String get_name() const = 0; - virtual List get_cmdline_args() const { return _cmdline; } + virtual List get_cmdline_args() const { + return _cmdline; + } virtual String get_model_name() const; void ensure_user_data_dir(); @@ -377,6 +383,11 @@ public: int sec; }; + struct DateTime { + Date date; + Time time; + }; + struct TimeZoneInfo { int bias; String name; @@ -389,6 +400,8 @@ public: virtual uint64_t get_unix_time() const; virtual uint64_t get_system_time_secs() const; virtual uint64_t get_system_time_msecs() const; + DateTime get_datetime_from_unix_time(int64_t unix_time_val) const; + int64_t get_unix_time_from_datetime(const DateTime &datetime) const; virtual void delay_usec(uint32_t p_usec) const = 0; virtual void add_frame_delay(bool p_can_draw); @@ -399,13 +412,17 @@ public: virtual bool can_draw() const = 0; - virtual bool is_userfs_persistent() const { return true; } + virtual bool is_userfs_persistent() const { + return true; + } bool is_stdout_verbose() const; bool is_stdout_debug_enabled() const; virtual void disable_crash_handler() {} - virtual bool is_disable_crash_handler() const { return false; } + virtual bool is_disable_crash_handler() const { + return false; + } virtual void initialize_debugging() {} enum CursorShape { @@ -441,7 +458,9 @@ public: virtual CursorShape get_cursor_shape() const; virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot); - virtual bool get_swap_ok_cancel() { return false; } + virtual bool get_swap_ok_cancel() { + return false; + } virtual void dump_memory_to_file(const char *p_file); virtual void dump_resources_to_file(const char *p_file); virtual void print_resources_in_use(bool p_short = false); @@ -452,7 +471,9 @@ public: virtual uint64_t get_dynamic_memory_usage() const; virtual uint64_t get_free_static_memory() const; - RenderThreadMode get_render_thread_mode() const { return _render_thread_mode; } + RenderThreadMode get_render_thread_mode() const { + return _render_thread_mode; + } virtual String get_locale() const; String get_locale_language() const; @@ -482,7 +503,9 @@ public: virtual String get_system_dir(SystemDir p_dir, bool p_shared_storage = true) const; - virtual Error move_to_trash(const String &p_path) { return FAILED; } + virtual Error move_to_trash(const String &p_path) { + return FAILED; + } virtual void set_no_window_mode(bool p_enable); virtual bool is_no_window_mode_enabled() const; @@ -591,16 +614,26 @@ public: void set_has_server_feature_callback(HasServerFeatureCallback p_callback); - bool is_layered_allowed() const { return _allow_layered; } - bool is_hidpi_allowed() const { return _allow_hidpi; } + bool is_layered_allowed() const { + return _allow_layered; + } + bool is_hidpi_allowed() const { + return _allow_hidpi; + } void set_restart_on_exit(bool p_restart, const List &p_restart_arguments); bool is_restart_on_exit_set() const; List get_restart_on_exit_arguments() const; - virtual bool request_permission(const String &p_name) { return true; } - virtual bool request_permissions() { return true; } - virtual Vector get_granted_permissions() const { return Vector(); } + virtual bool request_permission(const String &p_name) { + return true; + } + virtual bool request_permissions() { + return true; + } + virtual Vector get_granted_permissions() const { + return Vector(); + } virtual void process_and_drop_events() {} OS();