@@ -990,60 +990,68 @@ not present, current time as returned by localtime() is used.");
990
990
991
991
#ifdef HAVE_MKTIME
992
992
static PyObject *
993
- time_mktime (PyObject * self , PyObject * tup )
993
+ time_mktime (PyObject * self , PyObject * tm_tuple )
994
994
{
995
- struct tm buf ;
995
+ struct tm tm ;
996
996
time_t tt ;
997
- #ifdef _AIX
998
- time_t clk ;
999
- int year = buf .tm_year ;
1000
- int delta_days = 0 ;
1001
- #endif
1002
997
1003
- if (!gettmarg (tup , & buf ,
998
+ if (!gettmarg (tm_tuple , & tm ,
1004
999
"iiiiiiiii;mktime(): illegal time tuple argument" ))
1005
1000
{
1006
1001
return NULL ;
1007
1002
}
1008
- #ifndef _AIX
1009
- buf . tm_wday = -1 ; /* sentinel; original value ignored */
1010
- tt = mktime (& buf );
1011
- #else
1012
- /* year < 1902 or year > 2037 */
1013
- if (( buf .tm_year < 2 ) || ( buf .tm_year > 137 )) {
1014
- /* Issue # 19748: On AIX, mktime() doesn't report overflow error for
1015
- * timestamp < -2^31 or timestamp > 2**31-1. */
1003
+
1004
+ #ifdef _AIX
1005
+ /* bpo-19748: AIX mktime() valid range is 00:00:00 UTC, January 1, 1970
1006
+ to 03:14:07 UTC, January 19, 2038. Thanks to the workaround below,
1007
+ it is possible to support years in range [1902; 2037] */
1008
+ if (tm .tm_year < 2 || tm .tm_year > 137 ) {
1009
+ /* bpo- 19748: On AIX, mktime() does not report overflow error
1010
+ for timestamp < -2^31 or timestamp > 2**31-1. */
1016
1011
PyErr_SetString (PyExc_OverflowError ,
1017
1012
"mktime argument out of range" );
1018
1013
return NULL ;
1019
1014
}
1020
- year = buf .tm_year ;
1021
- /* year < 1970 - adjust buf.tm_year into legal range */
1022
- while (buf .tm_year < 70 ) {
1023
- buf .tm_year += 4 ;
1015
+
1016
+ /* bpo-34373: AIX mktime() has an integer overflow for years in range
1017
+ [1902; 1969]. Workaround the issue by using a year greater or equal than
1018
+ 1970 (tm_year >= 70): mktime() behaves correctly in that case
1019
+ (ex: properly report errors). tm_year and tm_wday are adjusted after
1020
+ mktime() call. */
1021
+ int orig_tm_year = tm .tm_year ;
1022
+ int delta_days = 0 ;
1023
+ while (tm .tm_year < 70 ) {
1024
+ /* Use 4 years to account properly leap years */
1025
+ tm .tm_year += 4 ;
1024
1026
delta_days -= (366 + (365 * 3 ));
1025
1027
}
1028
+ #endif
1026
1029
1027
- buf .tm_wday = -1 ;
1028
- clk = mktime (& buf );
1029
- buf .tm_year = year ;
1030
-
1031
- if ((buf .tm_wday != -1 ) && delta_days )
1032
- buf .tm_wday = (buf .tm_wday + delta_days ) % 7 ;
1030
+ tm .tm_wday = -1 ; /* sentinel; original value ignored */
1031
+ tt = mktime (& tm );
1033
1032
1034
- tt = clk + (delta_days * (24 * 3600 ));
1035
- #endif
1036
1033
/* Return value of -1 does not necessarily mean an error, but tm_wday
1037
1034
* cannot remain set to -1 if mktime succeeded. */
1038
1035
if (tt == (time_t )(-1 )
1039
1036
/* Return value of -1 does not necessarily mean an error, but
1040
1037
* tm_wday cannot remain set to -1 if mktime succeeded. */
1041
- && buf .tm_wday == -1 )
1038
+ && tm .tm_wday == -1 )
1042
1039
{
1043
1040
PyErr_SetString (PyExc_OverflowError ,
1044
1041
"mktime argument out of range" );
1045
1042
return NULL ;
1046
1043
}
1044
+
1045
+ #ifdef _AIX
1046
+ if (delta_days != 0 ) {
1047
+ tm .tm_year = orig_tm_year ;
1048
+ if (tm .tm_wday != -1 ) {
1049
+ tm .tm_wday = (tm .tm_wday + delta_days ) % 7 ;
1050
+ }
1051
+ tt += delta_days * (24 * 3600 );
1052
+ }
1053
+ #endif
1054
+
1047
1055
return PyFloat_FromDouble ((double )tt );
1048
1056
}
1049
1057
0 commit comments