Derick Rethans
Hi there!
I'm Derick, and I'm the primary maintainer of PHP's debugger, Xdebug. If you have questions, feel free to reach out to me by e-mail, Twitter, or IRC.
cheers, Derick
Timelib is a timezone and date/time library that can calculate local time, convert between timezones and parse textual descriptions of date/time information.
License: MIT License
<?php
strtotime("20888888888888888Ms");
ubsan complains:
parse_date.re:647:57: runtime error: signed integer overflow: 20888888888888888 * 1000 cannot be represented in type 'long long'
The relevant code are these multiplications:
Lines 650 to 656 in 09477f7
This only really means allowing to parse it, as it only pertains to leap seconds, which timelib doesn't support
Could you please update the readme file, to write more about it's usage ?
From PHP's https://bugs.php.net/bug.php?id=75038&edit=1:
derick@singlemalt:~/dev/timelib/tests $ ./tester-create-ts "2369-12-31" "" "UTC"
TS: 12622694400 | 2369-12-31 00:00:00 UTC UTC
derick@singlemalt:~/dev/timelib/tests $ ./tester-render-ts 12622694400 "UTC"
TYPE: 3 TS: 12622694400 | 2370-01-00 00:00:00 UTC UTC
Original issue: https://bugs.php.net/bug.php?id=76770
Examples: https://3v4l.org/ZBN3W
My PR for php-src: php/php-src#3514
I'm try apply patch, but tests failed (https://github.com/derickr/timelib/blob/master/tests/files/epoch-seconds.parseformat#L2). Tests correct?
The bug happens when parsing a time string that contains a timezone not immediately followed by a space
Already discovered here: https://stackoverflow.com/a/8988859
var_dump(date_create_from_format("D-M-d-H.i.s-T-Y", "Tue-Feb-25-10.21.25-CET-2020"));
var_dump(date_get_last_errors());
bool(false)
array(4) {
["warning_count"]=>
int(0)
["warnings"]=>
array(0) {
}
["error_count"]=>
int(2)
["errors"]=>
array(2) {
[20]=>
string(47) "The timezone could not be found in the database"
[28]=>
string(12) "Data missing"
}
}
var_dump(date_create_from_format("D-M-d-H.i.s-T -Y", "Tue-Feb-25-10.21.25-CET -2020"));
object(DateTime)#1 (3) {
["date"]=>
string(26) "2020-02-25 10:21:25.000000"
["timezone_type"]=>
int(2)
["timezone"]=>
string(3) "CET"
}
When compiling timelib with -O2
and GCC 8.1, the following compile warning is shown:
src/third_party/timelib-2018.01alpha1/parse_zoneinfo.c: In function ‘create_zone_index.constprop’:
src/third_party/timelib-2018.01alpha1/parse_zoneinfo.c:118:40: warning: ‘__builtin___snprintf_chk’ output may be truncated before the last format character [-Wformat-truncation=]
snprintf(fname, sizeof(fname), "%s%s%s", directory, TIMELIB_DIR_SEPARATOR, timezone /* canonical_tzname(timezone) */);
^
In file included from /usr/include/stdio.h:862,
from src/third_party/timelib-2018.01alpha1/timelib_private.h:70,
from src/third_party/timelib-2018.01alpha1/parse_zoneinfo.c:27:
/usr/include/x86_64-linux-gnu/bits/stdio2.h:64:10: note: ‘__builtin___snprintf_chk’ output 2 or more bytes (assuming 4097) into a destination of size 4096
return __builtin___snprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
__bos (__s), __fmt, __va_arg_pack ());
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Warnings like this:
parse_tz.c(408): error C2220: warning treated as error - no 'object' file generated
parse_tz.c(408): warning C4477: 'printf' : format string '%016lX' requires an argument of type 'unsigned long', but variadic argument 1 has type 'int64_t'
parse_tz.c(408): note: consider using '%llX' in the format string
parse_tz.c(408): note: consider using '%IX' in the format string
parse_tz.c(408): note: consider using '%I64X' in the format string
UTC and the Zulu time zone are not the same.
The Zulu time zone, abbreviated with "Z", is a military time zone with no offset to UTC.
$dt = new DateTime('2020-08-09T12:00Z');
var_dump($dt->getTimeZone()->getName());
At the moment the result is "Z": https://3v4l.org/nlHGM
This is correct, if the "Z" in the date-time string is interpreted as a time zone abbreviation.
But following ISO 8601, the "Z" is a designator for UTC (ISO 8601 doesn't handle time zone abbreviations).
https://en.wikipedia.org/wiki/ISO_8601#Time_zone_designators
So I would expect to get the "UTC" time zone, when passing an ISO 8601 string for UTC date-times.
But maybe it's not worth changing the behavior here. What do you think?
Hi love the functionality built into PHPs strtotime function. Am struggling to make it work stand alone. I’m attempting to parse a string and produce a UNIX UTC bit so far the number as always either 0 or 2038.
And chance of a usage example on how to parse and convert to time_t?
While the date_sub
handles both DST forward and backward, date_add
only handles backward... These lines
https://github.com/derickr/timelib/blob/master/interval.c#L162-L166
should be copied to
https://github.com/derickr/timelib/blob/master/interval.c#L128
gcc -O0 -ggdb3 -Wall -DHAVE_STDLIB_H -DHAVE_STRING_H -DHAVE_INTTYPES_H -I. -lm -o tests/tester-parse-interval tests/tester-parse-interval.c timelib.a
timelib.a(timelib.o): In function `timelib_decimal_hour_to_hms':
/home/martijn/github/timelib/timelib.c:221: undefined reference to `floor'
/home/martijn/github/timelib/timelib.c:222: undefined reference to `floor'
collect2: error: ld returned 1 exit status
make: *** [tests/tester-parse-interval] Error 1
The wrap around behavior of microseconds in do_range_limit_fraction() appears to be broken, since 1000000 µs are allowed. It seems the respective line should be:
if (*fraction >= 1000000) {
See also the respective PHP bug.
When running make, I get the following error:
In file included from timelib.h:24:0,
from tm2unixtime.c:21:
timelib_structs.h:24:28: fatal error: timelib_config.h: No such file or directory
#include "timelib_config.h"
There is a change in zic output in the IANA tzcode release 2018e:
zic now always generates TZif files where time type 0 is used for timestamps before the first transition. This simplifies the reading of TZif files and should not affect behavior of existing TZif readers because the same set of time types is used; only their internal indexes may have changed. This affects only the legacy zones EST5EDT, CST6CDT, MST7MDT, PST8PDT, CET, MET, and EET, which previously used nonzero types for these timestamps. Because of the type 0 change, zic no longer outputs a dummy transition at time -2**59 (before the Big Bang), as clients should no longer need this to handle historical timestamps correctly. This reverts a change introduced in 2013d and shrinks most TZif files by a few bytes.
Timelib relies on this information being there, and due to this change started rendering early timestamps incorrectly.
$ ./tester-render-ts -61626506832 "America/Belize"
Should show:
TYPE: 3 TS: -61626506832 | 0017-02-18 00:00:00 LMT America/Belize
But currently shows:
TYPE: 3 TS: -61626506832 | 0017-02-17 23:52:48 CST America/Belize
The IANA tzdata project recently switched the default generation with zic
from fat
to slim
files by default. timelib does not understand this format correctly, and hence should be able to provide a warning when it detects this format when parsing the file through timelib_parse_tzfile
.
Instead of using a multiplication calculation, it uses an iterative process which is magnitudes slower.
https://github.com/derickr/timelib/blob/master/unixtime2tm.c#L77-L81
For positive TS's, this is handled correctly:
https://github.com/derickr/timelib/blob/master/unixtime2tm.c#L52-L55
We don't use this library directly, however the current version merged in php has a number of bugs related to timediff.
$utc_tz = new DateTimeZone('UTC');
$curr_time = DateTime::createFromFormat('Y-m-d H:i:s.u', '2018-11-22 13:27:52.089635', $utc_tz);
$customer_time = DateTime::createFromFormat('Y-m-d H:i:s', '2018-11-22 13:27:52', $utc_tz);
print_r($curr_time->diff($customer_time, true));
print_r($curr_time->diff($customer_time, false));
There's less than a second between those 2 times, and yet result from both print_r() statements (with the "absolute" comparison on/off) is:
DateInterval Object
(
[y] => -1
[m] => 11
[d] => 30
[h] => 23
[i] => 59
[s] => 59
[f] => 0.910365
[weekday] => 0
[weekday_behavior] => 0
[first_last_day_of] => 0
[invert] => 0
[days] => 0
[special_type] => 0
[special_amount] => 0
[have_weekday_relative] => 0
[have_special_relative] => 0
)
This is beyond wrong. The older timelib also gave a wrong result for the microseconds, but at least it wasn't "out of this universe" wrong:
DateInterval Object
(
[y] => 0
[m] => 0
[d] => 0
[h] => 0
[i] => 0
[s] => 0
[f] => -0.089635
[weekday] => 0
[weekday_behavior] => 0
[first_last_day_of] => 0
[invert] => 0
[days] => 0
[special_type] => 0
[special_amount] => 0
[have_weekday_relative] => 0
[have_special_relative] => 0
)
Same result for either "absolute" parameter true/false. ("f" should be positive when absolute is true).
Currently whenever "first day of" or "last day of" prefixes a date time expression it will assume the user wants the first/last day of the month belonging to the following expression. This makes sense in the case of an expression such as first day of this month
or first day of July 2020
where the user is attempting to retrieve the first day of the corresponding month; however, since "(last | this | next) (week | year | fortnight | etc.)" are considered to be valid expressions on their own, they will provide the user with unexpected results.
If the current day is July 4th, 2020 and a user enters first day of this year
, it will result in "July 1st, 2020" rather than the expected "January 1st, 2020".
Add support for contextually determining what unit the user is attempting to retrieve the (first | last) day
within.
We get a bunch of valgrind warnings like this:
==5484== Conditional jump or move depends on uninitialised value(s)
==5484== at 0x4E2FE0: do_adjust_timezone (tm2unixtime.c:467)
==5484== by 0x4E3349: timelib_update_ts (tm2unixtime.c:511)
==5484== by 0x46EE49: php_date_date_set (php_date.c:3592)
==5484== by 0x46EF57: zif_date_date_set (php_date.c:3607)
==5484== by 0x1228582: ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_HANDLER (zend_vm_execute.h:983)
==5484== by 0x1228582: execute_ex (zend_vm_execute.h:61488)
==5484== by 0x1250B8E: zend_execute (zend_vm_execute.h:67896)
==5484== by 0xFA74BF: zend_execute_scripts (zend.c:1639)
==5484== by 0xE94CE8: php_execute_script (main.c:2607)
==5484== by 0x1256A7F: do_cli (php_cli.c:992)
==5484== by 0x125853D: main (php_cli.c:1384)
For example http://gcov.php.net/viewer.php?version=PHP_HEAD&func=valgrind&file=ext%2Fdate%2Ftests%2FDateTime_add-massive.phpt.
The relevant line is here:
Line 467 in 8e4110a
I'm not sure if this is a timelib issue, might also be a problem with how it's used in PHP.
While working on an implementation of the MessagePack Timestamp extension, I encountered some unexpected issues with parsing string dates with DateTime
. The lowest timestamp the extension can store is -292277022657-01-27 08:29:52 UTC
, and the highest is 292277026596-12-04 15:30:07.999999999 UTC
. When I feed these dates into the DataTime
constructor, I get:
var_dump((new DateTime("@-9223372036854775808"))->getTimestamp());
var_dump((new DateTime('-292277022657-01-27 08:29:52 UTC'))->getTimestamp());
var_dump((new DateTime('-292277022657-01-27 08:29:53 UTC'))->getTimestamp());
var_dump((new DateTime("@9223372036854775807"))->getTimestamp());
var_dump((new DateTime('292277026596-12-04 15:30:07 UTC'))->getTimestamp());
echo (new DateTime('2512370164-01-01 00:00:00Z'))->format(DATE_RFC3339_EXTENDED);
int(-9223372036854775807) // wrong, one second is lost
int(-9223372036854775808) // correct
int(-9223372036854775807) // correct
int(9223372036854775807) // correct
int(146011735807) // wrong, the year 292277026596 is parsed to 6596
2064-01-01T00:00:00.000+00:00 // wrong, the year 2512370164 is parsed to 2064
I understand that these can be hard to fix problems, but maybe it would at least be possible to detect such cases and throw an exception "Failed to parse time string
" (as is done, for example, for 15121370164-01-01 00:00:00Z
) instead of silently returning a wrong date? Now the user doesn't even know if they sent or received the wrong date.
In PHP, timezone_abbreviations_list() only lists from compiled in db, not PECL timezonedb. timezone_identifiers_list() works as expected with PECL timezonedb.
Comment to PHP Bug #78669 submission is that it looks like a timelib issue, and as such should be reported upstream (here).
Hi,
does this library support big endian systems?
I am interested mainly in PowerPC64 big endian system. I am seeing error code related to this library in MongoDB which uses this library.
Thank you for information,
M.
There is a recent 2021b release of the IANA timezone db: https://www.iana.org/time-zones. Can we make sure the internal timezone db stored inside timelib
is up-to-date with this recent release? If you give me some pointers on how to do it, I can also take care of it and send a PR.
In ISO 8601-1:2019 it is not allowed to combine weeks with any other component.
But we already support combining weeks with other components, except with days. I think this is inconsistent.
And in ISO 8601-2:2019 it is allowed to combine weeks and other components, including days.
Hi,
The code for TIMELIB_FORMAT_TIMEZONE_OFFSET_MINUTES
exists but isn't listed in the default_format_map
so isn't exposed by default
Is there a reason for this? It is being properly tested, but there's no way to use this through the PHP bindings.
Thanks,
The new "p" format should be supported by timelib_parse_from_format
.
See PHP bug #78673: Wrong results for DateTime->modify() with milliseconds
If you cherry pick this commit (mdashti@711278d), there's a test that timelib
fails to compile the timezone file for Africa/Casablanca
taken from /usr/share/zoneinfo
of an Amazon Linux 1
instance. The same issue happens on RHEL 6
, 7
and 8
.
I had to remove these files/directory in order to be able to run MongoDB on Amazon Linux 1, which depends on timelib
and fails to start-up if there's a problem with reading timezone files:
sudo rm -rf /usr/share/zoneinfo/Africa # not all of them were problematic
sudo rm -rf /usr/share/zoneinfo/America/Godthab
sudo rm -rf /usr/share/zoneinfo/America/Nuuk
sudo rm -rf /usr/share/zoneinfo/America/Santiago
sudo rm -rf /usr/share/zoneinfo/Asia # not all of them were problematic
sudo rm -rf /usr/share/zoneinfo/Chile # not all of them were problematic
sudo rm -rf /usr/share/zoneinfo/Iran
sudo rm -rf /usr/share/zoneinfo/Israel
sudo rm -rf /usr/share/zoneinfo/Pacific # not all of them were problematic
Can you please check what can be the source of this issue?
Please note that it does not happen with the 2018.01
release and everything works fine for the Amazon Linux 1
instance on that release.
Hey guys,
just wondering why the timelib sets the current time if using the following format:
$date = DateTime::createFromFormat('Y-m-d', '2018-02-05');
var_dump($date);
class DateTime#1 (3) {
public $date =>
string(26) "2018-02-05 15:14:58.000000"
public $timezone_type =>
int(3)
public $timezone =>
string(13) "Europe/Berlin"
}
Now, if I want to compare e.g. the same value against the first one after some time because I just would like to check if the date is the same, I will get weird issues:
$date1 = DateTime::createFromFormat('Y-m-d', '2018-02-05');
sleep(1);
$date2 = DateTime::createFromFormat('Y-m-d', '2018-02-05');
$date1 == $date2; // false
$date1->setTime(0, 0);
$date2->setTime(0, 0);
$date1 == $date2; // true
I don't get the reason, why the timelib would even interpret the time value at all since none is passed to createFromFormat
and (imho) supposed to be 0.
BTW: Sorry that I used PHP to provide examples but I guess you get what I mean.
timelib_do_rel_normalize()
does not normalize fractions by calling do_range_limit_fraction()
resulting in incorrect DateInterval
values.
Consider the dates: 2018-10-11 20:59:06.914653
and 2018-10-11 20:59:07.237419
they differ by 0.322766
seconds but diff()
is reported as string(16) "00:00:01.-677234"
when formatted via format('%H:%I:%S.%F')
Dump of DateInterval
object:
class DateInterval#32 (16) {
public $y =>
int(0)
public $m =>
int(0)
public $d =>
int(0)
public $h =>
int(0)
public $i =>
int(0)
public $s =>
int(1)
public $f =>
double(-0.677234)
public $weekday =>
int(0)
public $weekday_behavior =>
int(0)
public $first_last_day_of =>
int(0)
public $invert =>
int(0)
public $days =>
int(0)
public $special_type =>
int(0)
public $special_amount =>
int(0)
public $have_weekday_relative =>
int(0)
public $have_special_relative =>
int(0)
}
<?php
$startDate = new \DateTime('2018-10-11 20:59:06.914653');
$endDate = new \DateTime('2018-10-11 20:59:07.237419');
$interval = $startDate->diff($endDate);
var_dump($interval->format('%H:%I:%S.%F'));
string(16) "00:00:00.322766"
string(16) "00:00:01.-677234"
Hello there,
As I was browsing php's bugtracker, I stumbled upon this bug #42351 Unable to create dates with years <= -10000 and >= 10000 and I think the problem might be on this line:
Line 2147 in c3de2a9
While PHP's documentation states that the 'Y' format returns a four digit number, in reality it returns the exact number of years of a date. Consider this example:
$dateMax = new \DateTime('@'.PHP_INT_MAX);
echo $dateMax->format('Y'); //Prints 292277026596 - PHP 7.3 running on Debian x64
echo $dateMax->format('y'); //Prints 96
$dateError = DateTime::createFromFormat('Y-m-d', '11111-11-11'); // $dateError is false
$date = new \DateTime('11111-11-11');
echo $date->format('Y-m-d'); //2001-11-11
Although there are workarounds (such as feeding the timestamp with mktime, or adding /subtracting a DateInterval to/from a DateTime object), the weird behavior of the constructor should be fixed.
Creating a new DateTime with four digits of precision gives an unexpected result.
$time = new DateTimeImmutable('@' . '1508765076.3470');
echo $time->format('r') . "\n";
// Wed, 24 Oct 3517 13:24:36 +0000
$time = new DateTimeImmutable('@' . '1508765076.347000');
echo $time->format('r') . "\n";
// Mon, 23 Oct 2017 13:24:36 +0000
$time = new DateTimeImmutable('@' . '1508765076');
echo $time->format('r') . "\n";
// Mon, 23 Oct 2017 13:24:36 +0000
Currently only 6 digits of precision are supported. It seems as though supporting other levels of precision would be helpful.
Hi @derickr,
I've resolved most of the issues around modifying dates with relative times, however, in doing so, I ran into a bug I could use some help with.
In ext/date/lib/tm2unixtime.c
the do_adjust_timezone
function calls timelib_get_time_zone_info
passing in the current sse
. However, if you create a date with a positive timezone offset (I've been testing with Sydney) near a DST jump forward transition, I believe that it's taking the offset from the time in DST (in this case, +11 instead of +10), and when it subtracts it again, it's an hour off. This is problematic if you're trying to move directly to the 2am boundary. It ultimately ends up using the transition before the one that it should and doesn't realize it's in a transition.
I work with future dates often and submitted this bug where converting a timestamp to a local datetime doesn't seem to be accurate for future dates - https://bugs.php.net/bug.php?id=69806. It seems related to Daylight Saving Time not being applied for dates after the year 2038 32-bit integer cut-off. I just wanted to raise it as an issue as I'm running into it often working with future dates.
Thank you for your help.
I am a developer at LiteSpeed Technologies and am working on a thread-capable version of the PHP module to be included in the Open-LiteSpeed web server. During load testing, we got a thread-sanitizer message in parse_tz.c line 389 (see backtrace below) in a call to setlocale. setlocale is not a thread-safe function and this is expected, though not desired, behavior. We noted setlocale in a number of different locations throughout the code and recommend its removal.
�[1m�[31mWARNING: ThreadSanitizer: data race (pid=52259)
�[1m�[0m�[1m�[34m Write of size 8 at 0x7d040000d700 by thread T1 (mutexes: write M504):
�[1m�[0m #0 setlocale /home/abuild/rpmbuild/BUILD/llvm-3.8.0.src/stage2/../projects/compiler-rt/lib/tsan/../sanitizer_common/sanitizer_common_interceptors.inc:2523 (openlitespeed+0x000000524600)
#1 seek_to_tz_position /home/user/proj/openlitespeed/src/modules/mod_lsphp/php-7.2/ext/date/lib/parse_tz.c:389 (mod_lsphp72.so+0x0000002243cc)
#2 timelib_timezone_id_is_valid /home/user/proj/openlitespeed/src/modules/mod_lsphp/php-7.2/ext/date/lib/parse_tz.c:436 (mod_lsphp72.so+0x00000022430c)
#3 zif_date_default_timezone_set /home/user/proj/openlitespeed/src/modules/mod_lsphp/php-7.2/ext/date/php_date.c:4835 (mod_lsphp72.so+0x0000001777df)
#4 ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER /home/user/proj/openlitespeed/src/modules/mod_lsphp/php-7.2/Zend/zend_vm_execute.h:573 (mod_lsphp72.so+0x0000014a67c8)
#5 execute_ex /home/user/proj/openlitespeed/src/modules/mod_lsphp/php-7.2/Zend/zend_vm_execute.h:59726 (mod_lsphp72.so+0x0000013c3345)
#6 zend_execute /home/user/proj/openlitespeed/src/modules/mod_lsphp/php-7.2/Zend/zend_vm_execute.h:63763 (mod_lsphp72.so+0x0000013c3c60)
#7 zend_execute_scripts /home/user/proj/openlitespeed/src/modules/mod_lsphp/php-7.2/Zend/zend.c:1496 (mod_lsphp72.so+0x0000012d2adc)
#8 php_execute_script /home/user/proj/openlitespeed/src/modules/mod_lsphp/php-7.2/main/main.c:2592 (mod_lsphp72.so+0x0000010d17a9)
#9 lsiapi_execute_script /home/user/proj/openlitespeed/src/modules/mod_lsphp/php-7.2/sapi/mod_lsphp/mod_lsphp.c:1400 (mod_lsphp72.so+0x00000158ad02)
#10 lsiapi_module_main /home/user/proj/openlitespeed/src/modules/mod_lsphp/php-7.2/sapi/mod_lsphp/mod_lsphp.c:1509 (mod_lsphp72.so+0x000001586718)
#11 process_req /home/user/proj/openlitespeed/src/modules/mod_lsphp/php-7.2/sapi/mod_lsphp/mod_lsphp.c:1536 (mod_lsphp72.so+0x0000015847c5)
#12 mod_lsphp_begin_process /home/user/proj/openlitespeed/src/modules/mod_lsphp/php-7.2/sapi/mod_lsphp/mod_lsphp.c:1667 (mod_lsphp72.so+0x00000157f3a0)
#13 MtHandlerProcess(ls_lfnodei_s*) /home/user/proj/openlitespeed/src/lsiapi/modulehandler.cpp:46 (openlitespeed+0x00000088ced5)
#14 WorkCrew::workerRoutine(CrewWorker*) /home/user/proj/openlitespeed/src/thread/workcrew.cpp:448 (openlitespeed+0x000000944a11)
#15 CrewWorker::thr_main(void*) /home/user/proj/openlitespeed/src/thread/crewworker.cpp:36 (openlitespeed+0x00000094531e)
#16 Thread::start_routine(void*) /home/user/proj/openlitespeed/src/thread/thread.cpp:43 (openlitespeed+0x000000942657)
This was opened in the php bug net as Bug #75599 | Thread Sanitizer error.
The developer response was:
Thanks for the report. While timelib is a part of PHP, it's maintained in a separate repository https://github.com/derickr/timelib . The bundled timelib should not be patched, i would ask you to please file an issue to the upstream repository on GitHub. In PHP we could mitigate it by locking the corresponding function call, which is in this case not an optimal solution but would have to be done if no other solution is found. In general, there are several other places with setlocale() in the core that might need to be checked for the same pattern.
Thanks.
This is my request to have the fix made. Feel free to contact me directly if you'd like.
Bob Perper
[email protected]
I encountered this using PHP, and this PHP bug describes pretty much what happens
I made a PR for php7.4, but they referred me here, as this is the upstream library PHP uses.
However, it's not clear to me how exactly I can adapt my PR to this project, since there's a difference between the library files in the php project and this project.
Can you make the equivalent timezonedb.h
change here as you did in the PHP tree (php/php-src@871c5ab) a few days ago?
(From: php internals, 2017-06-22)
As mentioned on PHP doc the format is based on ISO 8601, but it doesn't respects, for instance, decimal values (eg. P2.5D
). Related bug.
To be discussed: should it allows values like P.5D
?
Commit c68f45b introduced timelib_malloc and friends to allow to override the memory allocators. Apparently, there are still some direct uses of malloc(), though.
Also it might be useful to document that timelib assumes infallible allocators.
macos 10.15.7
changed
error: unknown warning option '-Wmaybe-uninitialized'; did you mean '-Wuninitialized'?
[-Werror,-Wunknown-warning-option]
-Wuninitialized
ld: library not found for -l:libubsan.so
remove -l:libubsan.so
'long long' is a C++11 extension
append -std=c++11
ctest: tests/c/all_tests.cpp timelib.a ${C_TESTS}
$(CXX) -std=c++11 $(CPPFLAGS) $(LDFLAGS) tests/c/all_tests.cpp ${C_TESTS} timelib.a $(TEST_LDFLAGS) -o ctest
./date-from-string 8:00 Asia/Shanghai
TS: -3489445440343 | -108607-11-16 08:00:00 LMT Asia/Shanghai
TS: -3489445440343 | -108607-11-15 23:54:17 UTC UTC
Timestamp: -3489445440343000
I am using timelib to convert a date/time + timezone into a timestamp.
In Eastern Canada ("Canada/Eastern" timezone) DST will end on November 7. At 2am, it will be 1am. How can I configure timelib to differentiate Nov 7, 1:30am before the transition from Nov 7, 1:30am after the transition? Is there a way to indicate this in timelib_time ?
Code snippet:
timelib_time *t;
timelib_tzinfo *tzi;
t = timelib_time_ctor();
t->y = 2021;
t->m = 11;
t->d = 7;
t->h = 1;
t->i = 30;
t->s = 0;
t->us = 0;
tzi = cached_fetch_tzinfo("Canada/Eastern");
timelib_set_timezone(t, tzi);
timelib_update_ts(t, tzi);
timelib_unixtime2gmt(t, t->sse);
printf("UTC Timestamp (Jan 1st, 1970 Epoch): %lld\n", t->sse);
Here are the steps to reproduce the issue on Amazon Linux (but it's pretty similar to do it on RHEL 6, 7 and 8:
Launched an Amazon Linux instance and then:
re2c
Dependency:wget https://codeload.github.com/skvadrik/re2c/tar.gz/refs/tags/0.15.3
tar -xzvf 0.15.3
cd re2c-0.15.3
cd re2c
./autogen.sh
./configure
make
sudo make install
cd ..
cd ..
cpputest
Dependency:wget https://github.com/cpputest/cpputest/releases/download/latest-passing-build/cpputest-latest.tar.gz
tar -xzvf cpputest-latest.tar.gz
cd cpputest-latest
autoreconf . -i
./configure
make
sudo make install
cd ..
timelib
:git clone https://github.com/mdashti/timelib
cd timelib
make
And, now I get this error:
gcc -Wdeclaration-after-statement -O0 -ggdb3 -Wall -Werror -Wextra -fsanitize=undefined -fsanitize=address -Wmaybe-uninitialized -Wmissing-field-initializers -Wshadow -Wno-unused-parameter -pedantic -Wno-implicit-fallthrough -DHAVE_STDINT_H -DHAVE_GETTIMEOFDAY -DHAVE_UNISTD_H -DHAVE_DIRENT_H -I. -o tests/tester-parse-interval tests/tester-parse-interval.c timelib.a -lm -fsanitize=undefined -l:libubsan.so
/opt/mongodbtoolchain/revisions/a90382f2f4f7be99b003a345b0fc048eef574a82/stow/gcc-v3.9Wv/lib/gcc/x86_64-mongodb-linux/8.3.0/libasan.a(sanitizer_linux_libcdep.o): In function `__sanitizer::GetThreadStackTopAndBottom(bool, unsigned long*, unsigned long*)':
/data/mci/227539e2e07d42127bf6f4be032e6f3b/toolchain-builder/tmp/build-gcc-v3.sh-JXL/build/x86_64-mongodb-linux/libsanitizer/sanitizer_common/../../../../src/combined/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cc:106: undefined reference to `pthread_getattr_np'
/opt/mongodbtoolchain/revisions/a90382f2f4f7be99b003a345b0fc048eef574a82/stow/gcc-v3.9Wv/lib/gcc/x86_64-mongodb-linux/8.3.0/libasan.a(sanitizer_linux_libcdep.o): In function `__sanitizer::SetEnv(char const*, char const*)':
/data/mci/227539e2e07d42127bf6f4be032e6f3b/toolchain-builder/tmp/build-gcc-v3.sh-JXL/build/x86_64-mongodb-linux/libsanitizer/sanitizer_common/../../../../src/combined/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cc:118: undefined reference to `dlsym'
/opt/mongodbtoolchain/revisions/a90382f2f4f7be99b003a345b0fc048eef574a82/stow/gcc-v3.9Wv/lib/gcc/x86_64-mongodb-linux/8.3.0/libasan.a(sanitizer_linux_libcdep.o): In function `__sanitizer::InitTlsSize()':
/data/mci/227539e2e07d42127bf6f4be032e6f3b/toolchain-builder/tmp/build-gcc-v3.sh-JXL/build/x86_64-mongodb-linux/libsanitizer/sanitizer_common/../../../../src/combined/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cc:163: undefined reference to `dlsym'
/opt/mongodbtoolchain/revisions/a90382f2f4f7be99b003a345b0fc048eef574a82/stow/gcc-v3.9Wv/lib/gcc/x86_64-mongodb-linux/8.3.0/libasan.a(sanitizer_posix_libcdep.o): In function `__sanitizer::GetNamedMappingFd(char const*, unsigned long)':
/data/mci/227539e2e07d42127bf6f4be032e6f3b/toolchain-builder/tmp/build-gcc-v3.sh-JXL/build/x86_64-mongodb-linux/libsanitizer/sanitizer_common/../../../../src/combined/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cc:310: undefined reference to `shm_open'
/data/mci/227539e2e07d42127bf6f4be032e6f3b/toolchain-builder/tmp/build-gcc-v3.sh-JXL/build/x86_64-mongodb-linux/libsanitizer/sanitizer_common/../../../../src/combined/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cc:314: undefined reference to `shm_unlink'
/opt/mongodbtoolchain/revisions/a90382f2f4f7be99b003a345b0fc048eef574a82/stow/gcc-v3.9Wv/lib/gcc/x86_64-mongodb-linux/8.3.0/libasan.a(sanitizer_posix_libcdep.o): In function `__sanitizer::AdjustStackSize(void*)':
/data/mci/227539e2e07d42127bf6f4be032e6f3b/toolchain-builder/tmp/build-gcc-v3.sh-JXL/build/x86_64-mongodb-linux/libsanitizer/sanitizer_common/../../../../src/combined/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cc:383: undefined reference to `pthread_attr_setstacksize'
/opt/mongodbtoolchain/revisions/a90382f2f4f7be99b003a345b0fc048eef574a82/stow/gcc-v3.9Wv/lib/gcc/x86_64-mongodb-linux/8.3.0/libasan.a(sanitizer_symbolizer_posix_libcdep.o): In function `__sanitizer::Symbolizer::LateInitialize()':
/data/mci/227539e2e07d42127bf6f4be032e6f3b/toolchain-builder/tmp/build-gcc-v3.sh-JXL/build/x86_64-mongodb-linux/libsanitizer/sanitizer_common/../../../../src/combined/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc:77: undefined reference to `dlsym'
/opt/mongodbtoolchain/revisions/a90382f2f4f7be99b003a345b0fc048eef574a82/stow/gcc-v3.9Wv/lib/gcc/x86_64-mongodb-linux/8.3.0/libasan.a(asan_linux.o): In function `__asan::AsanDlSymNext(char const*)':
/data/mci/227539e2e07d42127bf6f4be032e6f3b/toolchain-builder/tmp/build-gcc-v3.sh-JXL/build/x86_64-mongodb-linux/libsanitizer/asan/../../../../src/combined/libsanitizer/asan/asan_linux.cc:188: undefined reference to `dlsym'
/opt/mongodbtoolchain/revisions/a90382f2f4f7be99b003a345b0fc048eef574a82/stow/gcc-v3.9Wv/lib/gcc/x86_64-mongodb-linux/8.3.0/libasan.a(asan_posix.o): In function `__asan::AsanTSDInit(void (*)(void*))':
/data/mci/227539e2e07d42127bf6f4be032e6f3b/toolchain-builder/tmp/build-gcc-v3.sh-JXL/build/x86_64-mongodb-linux/libsanitizer/asan/../../../../src/combined/libsanitizer/asan/asan_posix.cc:47: undefined reference to `pthread_key_create'
/opt/mongodbtoolchain/revisions/a90382f2f4f7be99b003a345b0fc048eef574a82/stow/gcc-v3.9Wv/lib/gcc/x86_64-mongodb-linux/8.3.0/libasan.a(asan_posix.o): In function `__asan::PlatformTSDDtor(void*)':
/data/mci/227539e2e07d42127bf6f4be032e6f3b/toolchain-builder/tmp/build-gcc-v3.sh-JXL/build/x86_64-mongodb-linux/libsanitizer/asan/../../../../src/combined/libsanitizer/asan/asan_posix.cc:64: undefined reference to `pthread_setspecific'
/opt/mongodbtoolchain/revisions/a90382f2f4f7be99b003a345b0fc048eef574a82/stow/gcc-v3.9Wv/lib/gcc/x86_64-mongodb-linux/8.3.0/libasan.a(asan_posix.o): In function `__asan::AsanTSDGet()':
/data/mci/227539e2e07d42127bf6f4be032e6f3b/toolchain-builder/tmp/build-gcc-v3.sh-JXL/build/x86_64-mongodb-linux/libsanitizer/asan/../../../../src/combined/libsanitizer/asan/asan_posix.cc:52: undefined reference to `pthread_getspecific'
/opt/mongodbtoolchain/revisions/a90382f2f4f7be99b003a345b0fc048eef574a82/stow/gcc-v3.9Wv/lib/gcc/x86_64-mongodb-linux/8.3.0/libasan.a(asan_posix.o): In function `__asan::AsanTSDSet(void*)':
/data/mci/227539e2e07d42127bf6f4be032e6f3b/toolchain-builder/tmp/build-gcc-v3.sh-JXL/build/x86_64-mongodb-linux/libsanitizer/asan/../../../../src/combined/libsanitizer/asan/asan_posix.cc:57: undefined reference to `pthread_setspecific'
/opt/mongodbtoolchain/revisions/a90382f2f4f7be99b003a345b0fc048eef574a82/stow/gcc-v3.9Wv/lib/gcc/x86_64-mongodb-linux/8.3.0/libasan.a(interception_linux.o): In function `__interception::GetRealFunctionAddress(char const*, unsigned long*, unsigned long, unsigned long)':
/data/mci/227539e2e07d42127bf6f4be032e6f3b/toolchain-builder/tmp/build-gcc-v3.sh-JXL/build/x86_64-mongodb-linux/libsanitizer/interception/../../../../src/combined/libsanitizer/interception/interception_linux.cc:29: undefined reference to `dlsym'
/opt/mongodbtoolchain/revisions/a90382f2f4f7be99b003a345b0fc048eef574a82/stow/gcc-v3.9Wv/lib/gcc/x86_64-mongodb-linux/8.3.0/libasan.a(interception_linux.o): In function `__interception::GetFuncAddrVer(char const*, char const*)':
/data/mci/227539e2e07d42127bf6f4be032e6f3b/toolchain-builder/tmp/build-gcc-v3.sh-JXL/build/x86_64-mongodb-linux/libsanitizer/interception/../../../../src/combined/libsanitizer/interception/interception_linux.cc:35: undefined reference to `dlvsym'
collect2: error: ld returned 1 exit status
make: *** [tests/tester-parse-interval] Error 1
Please note this issue is introduced after timelib-2018.01
based on our tests at MongoDB.
Ubsan reports an error for this code:
<?php
new DateTime('@21641666666666669708sun');
With message:
ext/date/lib/tm2unixtime.c:436:39: runtime error: signed integer overflow: 106751991167303 * 86400 cannot be represented in type 'long long'
At this line:
Line 436 in b78a481
Not sure what the expected behavior is when it comes to integer overflows in timelib.
Hi
There are timezones in timezonedb.h
which are not listed in timezonemap.h
(e.g. America/Sao_Paulo
). This causes problems in PHP, such as this one reported in the Symfony framework: symfony/symfony#26550.
This was discovered by a MongoDB user: see https://jira.mongodb.org/browse/SERVER-49217 for the bug report opened against the MongoDB SERVER code base. MongoDB offers a $dateFromString
expression, which is implemented using timelib's timelib_strtotime()
function.
The user's input string was something like this "2006-01-02T15:04:05.123456789Z". Note that this has nanosecond precision, so there are 9 digits after the "." character. However, the code which handles the SOAP format appears to only permit 8 digits of precision. I assume that this was a mistake, and that it should allow for 9 digits rather than 8. In particular, [this line of code|https://github.com/derickr/timelib/blob/8d5bf201437aa129ea0c686d2c56d11639d06099/parse_date.re#L1528] has a hard-coded constant of 9. However, this 9 incorporates the "." character, and therefore only permits 8 numeric digits after the ".". The date string above ("2006-01-02T15:04:05.123456789Z") therefore returns an error when passed to timelib_strtotime()
. The code appears to work as expected in my testing, parsing the date string to the expected timelib_time
, if the 9 is changed to a 10 in the aforementioned line of timelib code.
Contrary to timelib_strtotime()
, timelib_parse_from_format()
does not properly initialize the have_time
member of the resulting timelib_time
struct. Even if a time is given, have_time
appears to be always 0
.
The supplied test script (PHP, no C, sorry) shows identical results for date_create()
and date_create_from_format()
(what is expected); however debugging reveals that have_time
is 1
for date_create()
, but 0
for date_create_from_format()
:
<?php
$datestring = '2016-08-07 12:34:56';
var_dump(date_create($datestring));
var_dump(date_create_from_format('Y-m-d H:i:s', $datestring));
<?php
strtotime("10000000000000000 hour");
/home/nikic/php-src-fuzz/ext/date/lib/tm2unixtime.c:372:31: runtime error: signed integer overflow: 359999991717811200 * 100 cannot be represented in type 'long long'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /home/nikic/php-src-fuzz/ext/date/lib/tm2unixtime.c:372:31 in
Probably numbers with that many digits shouldn't be accepted in the first place...
// my main.c
#include <stdio.h>
#include <string.h>
#include "timelib.h"
#include "timelib_private.h"
int main(int argc, char **argv) {
timelib_time *t1, *t2;
char *tStr1, *tStr2;
tStr2 = "2020-03-01 00:00:00 PRC";
tStr1 = "2020-02-01 00:00:00 PRC";
t1 = timelib_strtotime(tStr1, strlen(tStr1), NULL, timelib_builtin_db(),
timelib_parse_tzfile);
t2 = timelib_strtotime(tStr2, strlen(tStr2), NULL, timelib_builtin_db(),
timelib_parse_tzfile);
timelib_update_ts(t1, t1->tz_info);
timelib_update_ts(t2, t2->tz_info);
timelib_rel_time *diff = timelib_diff(t1, t2);
// OutPut: diff Y:0,m:0
printf("diff Y:%lld,m:%lld", diff->y, diff->m);
}
// lib interval.c
// line 62
// l think if z is the same not need timeToGmt
timelib_apply_localtime(one, 0);
timelib_apply_localtime(two, 0);
// is this right?
if(one->z != two->z){
timelib_apply_localtime(one, 0);
timelib_apply_localtime(two, 0);
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.