@@ -213,8 +213,9 @@ static PHP_METHOD(MongoDB_BSON_UTCDateTime, toDateTime)
213
213
{
214
214
php_phongo_utcdatetime_t * intern ;
215
215
php_date_obj * datetime_obj ;
216
- char * sec ;
216
+ char * sec_str ;
217
217
size_t sec_len ;
218
+ timelib_sll sec , usec ;
218
219
219
220
intern = Z_UTCDATETIME_OBJ_P (getThis ());
220
221
@@ -223,11 +224,23 @@ static PHP_METHOD(MongoDB_BSON_UTCDateTime, toDateTime)
223
224
object_init_ex (return_value , php_date_get_date_ce ());
224
225
datetime_obj = Z_PHPDATE_P (return_value );
225
226
226
- sec_len = spprintf (& sec , 0 , "@%" PRId64 , intern -> milliseconds / 1000 );
227
- php_date_initialize (datetime_obj , sec , sec_len , NULL , NULL , 0 );
228
- efree (sec );
227
+ sec = intern -> milliseconds / 1000 ;
228
+ usec = (llabs (intern -> milliseconds ) % 1000 ) * 1000 ;
229
+ if (intern -> milliseconds < 0 && usec != 0 ) {
230
+ /* For dates before the unix epoch, we need to subtract the microseconds from the timestamp.
231
+ * Since we can't directly pass microseconds when calling php_date_initialize due to a bug in PHP,
232
+ * we manually decrement the timestamp and subtract the number of microseconds from a full seconds
233
+ * to store in the us field. */
234
+ sec -- ;
235
+ usec = 1000000 - usec ;
236
+ }
237
+
238
+ /* TODO PHP 8.1.6+: microseconds can be included in the format string */
239
+ sec_len = spprintf (& sec_str , 0 , "@%" PRId64 , sec );
240
+ php_date_initialize (datetime_obj , sec_str , sec_len , NULL , NULL , 0 );
241
+ efree (sec_str );
229
242
230
- datetime_obj -> time -> us = ( intern -> milliseconds % 1000 ) * 1000 ;
243
+ datetime_obj -> time -> us = usec ;
231
244
}
232
245
233
246
static PHP_METHOD (MongoDB_BSON_UTCDateTime , jsonSerialize )
0 commit comments