summaryrefslogtreecommitdiff
path: root/core/os/time.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/os/time.cpp')
-rw-r--r--core/os/time.cpp162
1 files changed, 94 insertions, 68 deletions
diff --git a/core/os/time.cpp b/core/os/time.cpp
index 5eae94279a..a30e2a906b 100644
--- a/core/os/time.cpp
+++ b/core/os/time.cpp
@@ -95,16 +95,21 @@ VARIANT_ENUM_CAST(Time::Weekday);
day = day_number_copy + 1; \
}
-#define VALIDATE_YMDHMS \
- ERR_FAIL_COND_V_MSG(month == 0, 0, "Invalid month value of: " + itos(month) + ", months are 1-indexed and cannot be 0. See the Time.Month enum for valid values."); \
- ERR_FAIL_COND_V_MSG(month > 12, 0, "Invalid month value of: " + itos(month) + ". See the Time.Month enum for valid values."); \
- ERR_FAIL_COND_V_MSG(hour > 23, 0, "Invalid hour value of: " + itos(hour) + "."); \
- ERR_FAIL_COND_V_MSG(minute > 59, 0, "Invalid minute value of: " + itos(minute) + "."); \
- ERR_FAIL_COND_V_MSG(second > 59, 0, "Invalid second value of: " + itos(second) + " (leap seconds are not supported)."); \
- /* Do this check after month is tested as valid. */ \
- ERR_FAIL_COND_V_MSG(day == 0, 0, "Invalid day value of: " + itos(month) + ", days are 1-indexed and cannot be 0."); \
- uint8_t days_in_this_month = MONTH_DAYS_TABLE[IS_LEAP_YEAR(year)][month - 1]; \
- ERR_FAIL_COND_V_MSG(day > days_in_this_month, 0, "Invalid day value of: " + itos(day) + " which is larger than the maximum for this month, " + itos(days_in_this_month) + ".");
+#define VALIDATE_YMDHMS(ret) \
+ ERR_FAIL_COND_V_MSG(month == 0, ret, "Invalid month value of: " + itos(month) + ", months are 1-indexed and cannot be 0. See the Time.Month enum for valid values."); \
+ ERR_FAIL_COND_V_MSG(month < 0, ret, "Invalid month value of: " + itos(month) + "."); \
+ ERR_FAIL_COND_V_MSG(month > 12, ret, "Invalid month value of: " + itos(month) + ". See the Time.Month enum for valid values."); \
+ ERR_FAIL_COND_V_MSG(hour > 23, ret, "Invalid hour value of: " + itos(hour) + "."); \
+ ERR_FAIL_COND_V_MSG(hour < 0, ret, "Invalid hour value of: " + itos(hour) + "."); \
+ ERR_FAIL_COND_V_MSG(minute > 59, ret, "Invalid minute value of: " + itos(minute) + "."); \
+ ERR_FAIL_COND_V_MSG(minute < 0, ret, "Invalid minute value of: " + itos(minute) + "."); \
+ ERR_FAIL_COND_V_MSG(second > 59, ret, "Invalid second value of: " + itos(second) + " (leap seconds are not supported)."); \
+ ERR_FAIL_COND_V_MSG(second < 0, ret, "Invalid second value of: " + itos(second) + "."); \
+ ERR_FAIL_COND_V_MSG(day == 0, ret, "Invalid day value of: " + itos(day) + ", days are 1-indexed and cannot be 0."); \
+ ERR_FAIL_COND_V_MSG(day < 0, ret, "Invalid day value of: " + itos(day) + "."); \
+ /* Do this check after month is tested as valid. */ \
+ uint8_t days_in_this_month = MONTH_DAYS_TABLE[IS_LEAP_YEAR(year)][month - 1]; \
+ ERR_FAIL_COND_V_MSG(day > days_in_this_month, ret, "Invalid day value of: " + itos(day) + " which is larger than the maximum for this month, " + itos(days_in_this_month) + ".");
#define YMD_TO_DAY_NUMBER \
/* The day number since Unix epoch (0-index). Days before 1970 are negative. */ \
@@ -124,61 +129,65 @@ VARIANT_ENUM_CAST(Time::Weekday);
} \
}
-#define PARSE_ISO8601_STRING \
- int64_t year = UNIX_EPOCH_YEAR_AD; \
- Month month = MONTH_JANUARY; \
- uint8_t day = 1; \
- uint8_t hour = 0; \
- uint8_t minute = 0; \
- uint8_t second = 0; \
- { \
- bool has_date = false, has_time = false; \
- String date, time; \
- if (p_datetime.find_char('T') > 0) { \
- has_date = has_time = true; \
- PackedStringArray array = p_datetime.split("T"); \
- date = array[0]; \
- time = array[1]; \
- } else if (p_datetime.find_char(' ') > 0) { \
- has_date = has_time = true; \
- PackedStringArray array = p_datetime.split(" "); \
- date = array[0]; \
- time = array[1]; \
- } else if (p_datetime.find_char('-', 1) > 0) { \
- has_date = true; \
- date = p_datetime; \
- } else if (p_datetime.find_char(':') > 0) { \
- has_time = true; \
- time = p_datetime; \
- } \
- /* Set the variables from the contents of the string. */ \
- if (has_date) { \
- PackedInt32Array array = date.split_ints("-", false); \
- year = array[0]; \
- month = (Month)array[1]; \
- day = array[2]; \
- /* Handle negative years. */ \
- if (p_datetime.find_char('-') == 0) { \
- year *= -1; \
- } \
- } \
- if (has_time) { \
- PackedInt32Array array = time.split_ints(":", false); \
- hour = array[0]; \
- minute = array[1]; \
- second = array[2]; \
- } \
+#define PARSE_ISO8601_STRING(ret) \
+ int64_t year = UNIX_EPOCH_YEAR_AD; \
+ Month month = MONTH_JANUARY; \
+ int day = 1; \
+ int hour = 0; \
+ int minute = 0; \
+ int second = 0; \
+ { \
+ bool has_date = false, has_time = false; \
+ String date, time; \
+ if (p_datetime.find_char('T') > 0) { \
+ has_date = has_time = true; \
+ PackedStringArray array = p_datetime.split("T"); \
+ ERR_FAIL_COND_V_MSG(array.size() < 2, ret, "Invalid ISO 8601 date/time string."); \
+ date = array[0]; \
+ time = array[1]; \
+ } else if (p_datetime.find_char(' ') > 0) { \
+ has_date = has_time = true; \
+ PackedStringArray array = p_datetime.split(" "); \
+ ERR_FAIL_COND_V_MSG(array.size() < 2, ret, "Invalid ISO 8601 date/time string."); \
+ date = array[0]; \
+ time = array[1]; \
+ } else if (p_datetime.find_char('-', 1) > 0) { \
+ has_date = true; \
+ date = p_datetime; \
+ } else if (p_datetime.find_char(':') > 0) { \
+ has_time = true; \
+ time = p_datetime; \
+ } \
+ /* Set the variables from the contents of the string. */ \
+ if (has_date) { \
+ PackedInt32Array array = date.split_ints("-", false); \
+ ERR_FAIL_COND_V_MSG(array.size() < 3, ret, "Invalid ISO 8601 date string."); \
+ year = array[0]; \
+ month = (Month)array[1]; \
+ day = array[2]; \
+ /* Handle negative years. */ \
+ if (p_datetime.find_char('-') == 0) { \
+ year *= -1; \
+ } \
+ } \
+ if (has_time) { \
+ PackedInt32Array array = time.split_ints(":", false); \
+ ERR_FAIL_COND_V_MSG(array.size() < 3, ret, "Invalid ISO 8601 time string."); \
+ hour = array[0]; \
+ minute = array[1]; \
+ second = array[2]; \
+ } \
}
#define EXTRACT_FROM_DICTIONARY \
/* Get all time values from the dictionary. If it doesn't exist, set the */ \
/* values to the default values for Unix epoch (1970-01-01 00:00:00). */ \
int64_t year = p_datetime.has(YEAR_KEY) ? int64_t(p_datetime[YEAR_KEY]) : UNIX_EPOCH_YEAR_AD; \
- Month month = Month((p_datetime.has(MONTH_KEY)) ? uint8_t(p_datetime[MONTH_KEY]) : 1); \
- uint8_t day = p_datetime.has(DAY_KEY) ? uint8_t(p_datetime[DAY_KEY]) : 1; \
- uint8_t hour = p_datetime.has(HOUR_KEY) ? uint8_t(p_datetime[HOUR_KEY]) : 0; \
- uint8_t minute = p_datetime.has(MINUTE_KEY) ? uint8_t(p_datetime[MINUTE_KEY]) : 0; \
- uint8_t second = p_datetime.has(SECOND_KEY) ? uint8_t(p_datetime[SECOND_KEY]) : 0;
+ Month month = Month((p_datetime.has(MONTH_KEY)) ? int(p_datetime[MONTH_KEY]) : 1); \
+ int day = p_datetime.has(DAY_KEY) ? int(p_datetime[DAY_KEY]) : 1; \
+ int hour = p_datetime.has(HOUR_KEY) ? int(p_datetime[HOUR_KEY]) : 0; \
+ int minute = p_datetime.has(MINUTE_KEY) ? int(p_datetime[MINUTE_KEY]) : 0; \
+ int second = p_datetime.has(SECOND_KEY) ? int(p_datetime[SECOND_KEY]) : 0;
Time *Time::singleton = nullptr;
@@ -252,8 +261,8 @@ String Time::get_time_string_from_unix_time(int64_t p_unix_time_val) const {
return vformat("%02d:%02d:%02d", hour, minute, second);
}
-Dictionary Time::get_datetime_dict_from_string(String p_datetime, bool p_weekday) const {
- PARSE_ISO8601_STRING
+Dictionary Time::get_datetime_dict_from_datetime_string(String p_datetime, bool p_weekday) const {
+ PARSE_ISO8601_STRING(Dictionary())
Dictionary dict;
dict[YEAR_KEY] = year;
dict[MONTH_KEY] = (uint8_t)month;
@@ -270,9 +279,10 @@ Dictionary Time::get_datetime_dict_from_string(String p_datetime, bool p_weekday
return dict;
}
-String Time::get_datetime_string_from_dict(Dictionary p_datetime, bool p_use_space) const {
+String Time::get_datetime_string_from_datetime_dict(const Dictionary p_datetime, bool p_use_space) const {
ERR_FAIL_COND_V_MSG(p_datetime.is_empty(), "", "Invalid datetime Dictionary: Dictionary is empty.");
EXTRACT_FROM_DICTIONARY
+ VALIDATE_YMDHMS("")
// vformat only supports up to 6 arguments, so we need to split this up into 2 parts.
String timestamp = vformat("%04d-%02d-%02d", year, (uint8_t)month, day);
if (p_use_space) {
@@ -283,21 +293,36 @@ String Time::get_datetime_string_from_dict(Dictionary p_datetime, bool p_use_spa
return timestamp;
}
-int64_t Time::get_unix_time_from_datetime_dict(Dictionary p_datetime) const {
+int64_t Time::get_unix_time_from_datetime_dict(const Dictionary p_datetime) const {
ERR_FAIL_COND_V_MSG(p_datetime.is_empty(), 0, "Invalid datetime Dictionary: Dictionary is empty");
EXTRACT_FROM_DICTIONARY
- VALIDATE_YMDHMS
+ VALIDATE_YMDHMS(0)
YMD_TO_DAY_NUMBER
return day_number * SECONDS_PER_DAY + hour * 3600 + minute * 60 + second;
}
int64_t Time::get_unix_time_from_datetime_string(String p_datetime) const {
- PARSE_ISO8601_STRING
- VALIDATE_YMDHMS
+ PARSE_ISO8601_STRING(-1)
+ VALIDATE_YMDHMS(0)
YMD_TO_DAY_NUMBER
return day_number * SECONDS_PER_DAY + hour * 3600 + minute * 60 + second;
}
+String Time::get_offset_string_from_offset_minutes(int64_t p_offset_minutes) const {
+ String sign;
+ if (p_offset_minutes < 0) {
+ sign = "-";
+ p_offset_minutes = -p_offset_minutes;
+ } else {
+ sign = "+";
+ }
+ // These two lines can be optimized to one instruction on x86 and others.
+ // Note that % is acceptable here only because we ensure it's positive.
+ int64_t offset_hours = p_offset_minutes / 60;
+ int64_t offset_minutes = p_offset_minutes % 60;
+ return vformat("%s%02d:%02d", sign, offset_hours, offset_minutes);
+}
+
Dictionary Time::get_datetime_dict_from_system(bool p_utc) const {
OS::Date date = OS::get_singleton()->get_date(p_utc);
OS::Time time = OS::get_singleton()->get_time(p_utc);
@@ -385,10 +410,11 @@ void Time::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_datetime_string_from_unix_time", "unix_time_val", "use_space"), &Time::get_datetime_string_from_unix_time, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_date_string_from_unix_time", "unix_time_val"), &Time::get_date_string_from_unix_time);
ClassDB::bind_method(D_METHOD("get_time_string_from_unix_time", "unix_time_val"), &Time::get_time_string_from_unix_time);
- ClassDB::bind_method(D_METHOD("get_datetime_dict_from_string", "datetime", "weekday"), &Time::get_datetime_dict_from_string);
- ClassDB::bind_method(D_METHOD("get_datetime_string_from_dict", "datetime", "use_space"), &Time::get_datetime_string_from_dict);
+ ClassDB::bind_method(D_METHOD("get_datetime_dict_from_datetime_string", "datetime", "weekday"), &Time::get_datetime_dict_from_datetime_string);
+ ClassDB::bind_method(D_METHOD("get_datetime_string_from_datetime_dict", "datetime", "use_space"), &Time::get_datetime_string_from_datetime_dict);
ClassDB::bind_method(D_METHOD("get_unix_time_from_datetime_dict", "datetime"), &Time::get_unix_time_from_datetime_dict);
ClassDB::bind_method(D_METHOD("get_unix_time_from_datetime_string", "datetime"), &Time::get_unix_time_from_datetime_string);
+ ClassDB::bind_method(D_METHOD("get_offset_string_from_offset_minutes", "offset_minutes"), &Time::get_offset_string_from_offset_minutes);
ClassDB::bind_method(D_METHOD("get_datetime_dict_from_system", "utc"), &Time::get_datetime_dict_from_system, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_date_dict_from_system", "utc"), &Time::get_date_dict_from_system, DEFVAL(false));