Skip to content

Commit f9aa6c0

Browse files
Merge v1.19 into master (#1626)
2 parents a7091e8 + 9e9b082 commit f9aa6c0

File tree

3 files changed

+85
-5
lines changed

3 files changed

+85
-5
lines changed

src/BSON/UTCDateTime.c

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616

1717
#include <math.h>
18+
#include <inttypes.h>
1819

1920
#include <php.h>
2021
#include <zend_smart_str.h>
@@ -130,19 +131,32 @@ static void php_phongo_utcdatetime_to_php_date(zval* return_value, const zval* t
130131
{
131132
php_phongo_utcdatetime_t* intern;
132133
php_date_obj* datetime_obj;
133-
char* sec;
134+
char* sec_str;
134135
size_t sec_len;
136+
int64_t sec, usec;
135137

136138
intern = Z_UTCDATETIME_OBJ_P(this);
137139

138140
object_init_ex(return_value, ce);
139141
datetime_obj = Z_PHPDATE_P(return_value);
140142

141-
sec_len = spprintf(&sec, 0, "@%" PRId64, intern->milliseconds / 1000);
142-
php_date_initialize(datetime_obj, sec, sec_len, NULL, NULL, 0);
143-
efree(sec);
143+
sec = intern->milliseconds / 1000;
144+
usec = (llabs(intern->milliseconds) % 1000) * 1000;
145+
if (intern->milliseconds < 0 && usec != 0) {
146+
/* For dates before the unix epoch, we need to subtract the microseconds from the timestamp.
147+
* Since we can't directly pass microseconds when calling php_date_initialize due to a bug in PHP,
148+
* we manually decrement the timestamp and subtract the number of microseconds from a full seconds
149+
* to store in the us field. */
150+
sec--;
151+
usec = 1000000 - usec;
152+
}
153+
154+
/* TODO PHP 8.1.7+: microseconds can be included in the format string */
155+
sec_len = spprintf(&sec_str, 0, "@%" PRId64, sec);
156+
php_date_initialize(datetime_obj, sec_str, sec_len, NULL, NULL, 0);
157+
efree(sec_str);
144158

145-
datetime_obj->time->us = (intern->milliseconds % 1000) * 1000;
159+
datetime_obj->time->us = usec;
146160
}
147161

148162
/* Construct a new BSON UTCDateTime type from either the current time,
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--TEST--
2+
MongoDB\BSON\UTCDateTime::toDateTime() with dates before the Unix epoch
3+
--INI--
4+
date.timezone=UTC
5+
--FILE--
6+
<?php
7+
8+
$dates = [
9+
'1960-01-01 12:12:12.1',
10+
'1969-12-31 23:59:59.999',
11+
];
12+
13+
foreach ($dates as $date) {
14+
$dateTime = new \DateTimeImmutable($date);
15+
echo $dateTime->format(DateTimeInterface::RFC3339_EXTENDED), PHP_EOL;
16+
17+
$utcDateTime = new MongoDB\BSON\UTCDateTime($dateTime);
18+
19+
$newDate = $utcDateTime->toDateTime();
20+
echo $newDate->format(DateTimeInterface::RFC3339_EXTENDED), PHP_EOL, PHP_EOL;
21+
}
22+
23+
?>
24+
===DONE===
25+
<?php exit(0); ?>
26+
--EXPECT--
27+
1960-01-01T12:12:12.100+00:00
28+
1960-01-01T12:12:12.100+00:00
29+
30+
1969-12-31T23:59:59.999+00:00
31+
1969-12-31T23:59:59.999+00:00
32+
33+
===DONE===
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--TEST--
2+
MongoDB\BSON\UTCDateTime::toDateTimeImmutable() with dates before the Unix epoch
3+
--INI--
4+
date.timezone=UTC
5+
--FILE--
6+
<?php
7+
8+
$dates = [
9+
'1960-01-01 12:12:12.1',
10+
'1969-12-31 23:59:59.999',
11+
];
12+
13+
foreach ($dates as $date) {
14+
$dateTime = new \DateTimeImmutable($date);
15+
echo $dateTime->format(DateTimeInterface::RFC3339_EXTENDED), PHP_EOL;
16+
17+
$utcDateTime = new MongoDB\BSON\UTCDateTime($dateTime);
18+
19+
$newDate = $utcDateTime->toDateTimeImmutable();
20+
echo $newDate->format(DateTimeInterface::RFC3339_EXTENDED), PHP_EOL, PHP_EOL;
21+
}
22+
23+
?>
24+
===DONE===
25+
<?php exit(0); ?>
26+
--EXPECT--
27+
1960-01-01T12:12:12.100+00:00
28+
1960-01-01T12:12:12.100+00:00
29+
30+
1969-12-31T23:59:59.999+00:00
31+
1969-12-31T23:59:59.999+00:00
32+
33+
===DONE===

0 commit comments

Comments
 (0)