Explorar o código

fix #20390 :get_unix_time_from_datetime and get_date_time_from_unix_time can handle time before year 1970 now

RaphaelHunter %!s(int64=7) %!d(string=hai) anos
pai
achega
43825dce47
Modificáronse 2 ficheiros con 33 adicións e 26 borrados
  1. 31 24
      core/bind/core_bind.cpp
  2. 2 2
      core/bind/core_bind.h

+ 31 - 24
core/bind/core_bind.cpp

@@ -658,7 +658,7 @@ Dictionary _OS::get_time(bool utc) const {
  *
  * @return epoch calculated
  */
-uint64_t _OS::get_unix_time_from_datetime(Dictionary datetime) const {
+int64_t _OS::get_unix_time_from_datetime(Dictionary datetime) const {
 
 	// Bunch of conversion constants
 	static const unsigned int SECONDS_PER_MINUTE = 60;
@@ -703,13 +703,18 @@ uint64_t _OS::get_unix_time_from_datetime(Dictionary datetime) const {
 	// 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;
 
-	uint64_t SECONDS_FROM_YEARS_PAST = 0;
-	for (unsigned int iyear = EPOCH_YR; iyear < year; iyear++) {
-
-		SECONDS_FROM_YEARS_PAST += YEARSIZE(iyear) * 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;
+		}
 	}
 
-	uint64_t epoch =
+	int64_t epoch =
 			second +
 			minute * SECONDS_PER_MINUTE +
 			hour * SECONDS_PER_HOUR +
@@ -732,34 +737,36 @@ uint64_t _OS::get_unix_time_from_datetime(Dictionary datetime) const {
  *
  * @return dictionary of date and time values
  */
-Dictionary _OS::get_datetime_from_unix_time(uint64_t unix_time_val) const {
-
-	// Just fail if unix time is negative (when interpreted as an int).
-	//  This means the user passed in a negative value by accident
-	ERR_EXPLAIN("unix_time_val was really huge!" + itos(unix_time_val) + " You probably passed in a negative value!");
-	ERR_FAIL_COND_V((int64_t)unix_time_val < 0, Dictionary());
+Dictionary _OS::get_datetime_from_unix_time(int64_t unix_time_val) const {
 
 	OS::Date date;
 	OS::Time time;
 
-	unsigned long dayclock, dayno;
+	long dayclock, dayno;
 	int year = EPOCH_YR;
 
-	dayclock = (unsigned long)unix_time_val % SECS_DAY;
-	dayno = (unsigned long)unix_time_val / SECS_DAY;
+	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 - 3) % 7 + 7);
+		do {
+			year--;
+			dayno += YEARSIZE(year);
+		} while (dayno < 0);
+	}
 
 	time.sec = dayclock % 60;
 	time.min = (dayclock % 3600) / 60;
 	time.hour = dayclock / 3600;
-
-	/* day 0 was a thursday */
-	date.weekday = static_cast<OS::Weekday>((dayno + 4) % 7);
-
-	while (dayno >= YEARSIZE(year)) {
-		dayno -= YEARSIZE(year);
-		year++;
-	}
-
 	date.year = year;
 
 	size_t imonth = 0;

+ 2 - 2
core/bind/core_bind.h

@@ -270,8 +270,8 @@ public:
 	Dictionary get_date(bool utc) const;
 	Dictionary get_time(bool utc) const;
 	Dictionary get_datetime(bool utc) const;
-	Dictionary get_datetime_from_unix_time(uint64_t unix_time_val) const;
-	uint64_t get_unix_time_from_datetime(Dictionary datetime) 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;
 	uint64_t get_unix_time() const;
 	uint64_t get_system_time_secs() const;