Skip to content

Commit d5b98c7

Browse files
committed
[PoC] Improve performance of date formatting
1 parent 1faf17b commit d5b98c7

File tree

1 file changed

+75
-70
lines changed

1 file changed

+75
-70
lines changed

ext/date/php_date.c

Lines changed: 75 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -672,13 +672,21 @@ static const char *php_date_short_day_name(timelib_sll y, timelib_sll m, timelib
672672
}
673673
/* }}} */
674674

675+
static void smart_str_append_long_outline(smart_str *dest, zend_long num)
676+
{
677+
smart_str_append_long(dest, num);
678+
}
679+
680+
static void smart_str_appends_outline(smart_str *dest, const char *src)
681+
{
682+
smart_str_appends(dest, src);
683+
}
684+
675685
/* {{{ date_format - (gm)date helper */
676686
static zend_string *date_format(const char *format, size_t format_len, const timelib_time *t, bool localtime)
677687
{
678688
smart_str string = {0};
679689
size_t i;
680-
int length = 0;
681-
char buffer[97];
682690
timelib_time_offset *offset = NULL;
683691
timelib_sll isoweek, isoyear;
684692
bool rfc_colon;
@@ -717,88 +725,88 @@ static zend_string *date_format(const char *format, size_t format_len, const tim
717725
rfc_colon = false;
718726
switch (format[i]) {
719727
/* day */
720-
case 'd': length = slprintf(buffer, sizeof(buffer), "%02d", (int) t->d); break;
721-
case 'D': length = slprintf(buffer, sizeof(buffer), "%s", php_date_short_day_name(t->y, t->m, t->d)); break;
722-
case 'j': length = slprintf(buffer, sizeof(buffer), "%d", (int) t->d); break;
723-
case 'l': length = slprintf(buffer, sizeof(buffer), "%s", php_date_full_day_name(t->y, t->m, t->d)); break;
724-
case 'S': length = slprintf(buffer, sizeof(buffer), "%s", english_suffix(t->d)); break;
725-
case 'w': length = slprintf(buffer, sizeof(buffer), "%d", (int) timelib_day_of_week(t->y, t->m, t->d)); break;
726-
case 'N': length = slprintf(buffer, sizeof(buffer), "%d", (int) timelib_iso_day_of_week(t->y, t->m, t->d)); break;
727-
case 'z': length = slprintf(buffer, sizeof(buffer), "%d", (int) timelib_day_of_year(t->y, t->m, t->d)); break;
728+
case 'd': smart_str_append_printf(&string, "%02d", (int) t->d); break;
729+
case 'D': smart_str_appends_outline(&string, php_date_short_day_name(t->y, t->m, t->d)); break;
730+
case 'j': smart_str_append_long_outline(&string, (int) t->d); break;
731+
case 'l': smart_str_appends_outline(&string, php_date_full_day_name(t->y, t->m, t->d)); break;
732+
case 'S': smart_str_appends_outline(&string, english_suffix(t->d)); break;
733+
case 'w': smart_str_append_long_outline(&string, (int) timelib_day_of_week(t->y, t->m, t->d)); break;
734+
case 'N': smart_str_append_long_outline(&string, (int) timelib_iso_day_of_week(t->y, t->m, t->d)); break;
735+
case 'z': smart_str_append_long_outline(&string, (int) timelib_day_of_year(t->y, t->m, t->d)); break;
728736

729737
/* week */
730738
case 'W':
731739
if(!weekYearSet) { timelib_isoweek_from_date(t->y, t->m, t->d, &isoweek, &isoyear); weekYearSet = 1; }
732-
length = slprintf(buffer, sizeof(buffer), "%02d", (int) isoweek); break; /* iso weeknr */
740+
smart_str_append_printf(&string, "%02d", (int) isoweek); break; /* iso weeknr */
733741
case 'o':
734742
if(!weekYearSet) { timelib_isoweek_from_date(t->y, t->m, t->d, &isoweek, &isoyear); weekYearSet = 1; }
735-
length = slprintf(buffer, sizeof(buffer), ZEND_LONG_FMT, (zend_long) isoyear); break; /* iso year */
743+
smart_str_append_long_outline(&string, (zend_long) isoyear); break; /* iso year */
736744

737745
/* month */
738-
case 'F': length = slprintf(buffer, sizeof(buffer), "%s", mon_full_names[t->m - 1]); break;
739-
case 'm': length = slprintf(buffer, sizeof(buffer), "%02d", (int) t->m); break;
740-
case 'M': length = slprintf(buffer, sizeof(buffer), "%s", mon_short_names[t->m - 1]); break;
741-
case 'n': length = slprintf(buffer, sizeof(buffer), "%d", (int) t->m); break;
742-
case 't': length = slprintf(buffer, sizeof(buffer), "%d", (int) timelib_days_in_month(t->y, t->m)); break;
746+
case 'F': smart_str_appends_outline(&string, mon_full_names[t->m - 1]); break;
747+
case 'm': smart_str_append_printf(&string, "%02d", (int) t->m); break;
748+
case 'M': smart_str_appends_outline(&string, mon_short_names[t->m - 1]); break;
749+
case 'n': smart_str_append_long_outline(&string, (int) t->m); break;
750+
case 't': smart_str_append_long_outline(&string, (int) timelib_days_in_month(t->y, t->m)); break;
743751

744752
/* year */
745-
case 'L': length = slprintf(buffer, sizeof(buffer), "%d", timelib_is_leap((int) t->y)); break;
746-
case 'y': length = slprintf(buffer, sizeof(buffer), "%02d", (int) (t->y % 100)); break;
747-
case 'Y': length = slprintf(buffer, sizeof(buffer), "%s%04lld", t->y < 0 ? "-" : "", php_date_llabs((timelib_sll) t->y)); break;
748-
case 'x': length = slprintf(buffer, sizeof(buffer), "%s%04lld", t->y < 0 ? "-" : (t->y >= 10000 ? "+" : ""), php_date_llabs((timelib_sll) t->y)); break;
749-
case 'X': length = slprintf(buffer, sizeof(buffer), "%s%04lld", t->y < 0 ? "-" : "+", php_date_llabs((timelib_sll) t->y)); break;
753+
case 'L': smart_str_append_long_outline(&string, timelib_is_leap((int) t->y)); break;
754+
case 'y': smart_str_append_printf(&string, "%02d", (int) (t->y % 100)); break;
755+
case 'Y': smart_str_append_printf(&string, "%s%04lld", t->y < 0 ? "-" : "", php_date_llabs((timelib_sll) t->y)); break;
756+
case 'x': smart_str_append_printf(&string, "%s%04lld", t->y < 0 ? "-" : (t->y >= 10000 ? "+" : ""), php_date_llabs((timelib_sll) t->y)); break;
757+
case 'X': smart_str_append_printf(&string, "%s%04lld", t->y < 0 ? "-" : "+", php_date_llabs((timelib_sll) t->y)); break;
750758

751759
/* time */
752-
case 'a': length = slprintf(buffer, sizeof(buffer), "%s", t->h >= 12 ? "pm" : "am"); break;
753-
case 'A': length = slprintf(buffer, sizeof(buffer), "%s", t->h >= 12 ? "PM" : "AM"); break;
760+
case 'a': smart_str_appends_outline(&string, t->h >= 12 ? "pm" : "am"); break;
761+
case 'A': smart_str_appends_outline(&string, t->h >= 12 ? "PM" : "AM"); break;
754762
case 'B': {
755763
int retval = ((((long)t->sse)-(((long)t->sse) - ((((long)t->sse) % 86400) + 3600))) * 10);
756764
if (retval < 0) {
757765
retval += 864000;
758766
}
759767
/* Make sure to do this on a positive int to avoid rounding errors */
760768
retval = (retval / 864) % 1000;
761-
length = slprintf(buffer, sizeof(buffer), "%03d", retval);
769+
smart_str_append_printf(&string, "%03d", retval);
762770
break;
763771
}
764-
case 'g': length = slprintf(buffer, sizeof(buffer), "%d", (t->h % 12) ? (int) t->h % 12 : 12); break;
765-
case 'G': length = slprintf(buffer, sizeof(buffer), "%d", (int) t->h); break;
766-
case 'h': length = slprintf(buffer, sizeof(buffer), "%02d", (t->h % 12) ? (int) t->h % 12 : 12); break;
767-
case 'H': length = slprintf(buffer, sizeof(buffer), "%02d", (int) t->h); break;
768-
case 'i': length = slprintf(buffer, sizeof(buffer), "%02d", (int) t->i); break;
769-
case 's': length = slprintf(buffer, sizeof(buffer), "%02d", (int) t->s); break;
770-
case 'u': length = slprintf(buffer, sizeof(buffer), "%06d", (int) floor(t->us)); break;
771-
case 'v': length = slprintf(buffer, sizeof(buffer), "%03d", (int) floor(t->us / 1000)); break;
772+
case 'g': smart_str_append_long_outline(&string, (t->h % 12) ? (int) t->h % 12 : 12); break;
773+
case 'G': smart_str_append_long_outline(&string, (int) t->h); break;
774+
case 'h': smart_str_append_printf(&string, "%02d", (t->h % 12) ? (int) t->h % 12 : 12); break;
775+
case 'H': smart_str_append_printf(&string, "%02d", (int) t->h); break;
776+
case 'i': smart_str_append_printf(&string, "%02d", (int) t->i); break;
777+
case 's': smart_str_append_printf(&string, "%02d", (int) t->s); break;
778+
case 'u': smart_str_append_printf(&string, "%06d", (int) floor(t->us)); break;
779+
case 'v': smart_str_append_printf(&string, "%03d", (int) floor(t->us / 1000)); break;
772780

773781
/* timezone */
774-
case 'I': length = slprintf(buffer, sizeof(buffer), "%d", localtime ? offset->is_dst : 0); break;
782+
case 'I': smart_str_append_long_outline(&string, localtime ? offset->is_dst : 0); break;
775783
case 'p':
776784
if (!localtime || strcmp(offset->abbr, "UTC") == 0 || strcmp(offset->abbr, "Z") == 0 || strcmp(offset->abbr, "GMT+0000") == 0) {
777-
length = slprintf(buffer, sizeof(buffer), "%s", "Z");
785+
smart_str_appendc(&string, 'Z');
778786
break;
779787
}
780788
ZEND_FALLTHROUGH;
781789
case 'P': rfc_colon = true; ZEND_FALLTHROUGH;
782-
case 'O': length = slprintf(buffer, sizeof(buffer), "%c%02d%s%02d",
790+
case 'O': smart_str_append_printf(&string, "%c%02d%s%02d",
783791
localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
784792
localtime ? abs(offset->offset / 3600) : 0,
785793
rfc_colon ? ":" : "",
786794
localtime ? abs((offset->offset % 3600) / 60) : 0
787795
);
788796
break;
789-
case 'T': length = slprintf(buffer, sizeof(buffer), "%s", localtime ? offset->abbr : "GMT"); break;
797+
case 'T': smart_str_appends_outline(&string, localtime ? offset->abbr : "GMT"); break;
790798
case 'e': if (!localtime) {
791-
length = slprintf(buffer, sizeof(buffer), "%s", "UTC");
799+
smart_str_appends_outline(&string, "UTC");
792800
} else {
793801
switch (t->zone_type) {
794802
case TIMELIB_ZONETYPE_ID:
795-
length = slprintf(buffer, sizeof(buffer), "%s", t->tz_info->name);
803+
smart_str_appends_outline(&string, t->tz_info->name);
796804
break;
797805
case TIMELIB_ZONETYPE_ABBR:
798-
length = slprintf(buffer, sizeof(buffer), "%s", offset->abbr);
806+
smart_str_appends_outline(&string, offset->abbr);
799807
break;
800808
case TIMELIB_ZONETYPE_OFFSET:
801-
length = slprintf(buffer, sizeof(buffer), "%c%02d:%02d",
809+
smart_str_append_printf(&string, "%c%02d:%02d",
802810
((offset->offset < 0) ? '-' : '+'),
803811
abs(offset->offset / 3600),
804812
abs((offset->offset % 3600) / 60)
@@ -807,18 +815,18 @@ static zend_string *date_format(const char *format, size_t format_len, const tim
807815
}
808816
}
809817
break;
810-
case 'Z': length = slprintf(buffer, sizeof(buffer), "%d", localtime ? offset->offset : 0); break;
818+
case 'Z': smart_str_append_long_outline(&string, localtime ? offset->offset : 0); break;
811819

812820
/* full date/time */
813-
case 'c': length = slprintf(buffer, sizeof(buffer), "%04" ZEND_LONG_FMT_SPEC "-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
821+
case 'c': smart_str_append_printf(&string, "%04" ZEND_LONG_FMT_SPEC "-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
814822
(zend_long) t->y, (int) t->m, (int) t->d,
815823
(int) t->h, (int) t->i, (int) t->s,
816824
localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
817825
localtime ? abs(offset->offset / 3600) : 0,
818826
localtime ? abs((offset->offset % 3600) / 60) : 0
819827
);
820828
break;
821-
case 'r': length = slprintf(buffer, sizeof(buffer), "%3s, %02d %3s %04" ZEND_LONG_FMT_SPEC " %02d:%02d:%02d %c%02d%02d",
829+
case 'r': smart_str_append_printf(&string, "%3s, %02d %3s %04" ZEND_LONG_FMT_SPEC " %02d:%02d:%02d %c%02d%02d",
822830
php_date_short_day_name(t->y, t->m, t->d),
823831
(int) t->d, mon_short_names[t->m - 1],
824832
(zend_long) t->y, (int) t->h, (int) t->i, (int) t->s,
@@ -827,13 +835,12 @@ static zend_string *date_format(const char *format, size_t format_len, const tim
827835
localtime ? abs((offset->offset % 3600) / 60) : 0
828836
);
829837
break;
830-
case 'U': length = slprintf(buffer, sizeof(buffer), "%lld", (timelib_sll) t->sse); break;
838+
case 'U': smart_str_append_printf(&string, "%lld", (timelib_sll) t->sse); break;
831839

832840
case '\\': if (i < format_len) i++; ZEND_FALLTHROUGH;
833841

834-
default: buffer[0] = format[i]; buffer[1] = '\0'; length = 1; break;
842+
default: smart_str_appendc(&string, format[i]); break;
835843
}
836-
smart_str_appendl(&string, buffer, length);
837844
}
838845

839846
smart_str_0(&string);
@@ -4929,8 +4936,7 @@ static zend_string *date_interval_format(const char *format, size_t format_len,
49294936
{
49304937
smart_str string = {0};
49314938
size_t i;
4932-
int length, have_format_spec = 0;
4933-
char buffer[33];
4939+
int have_format_spec = 0;
49344940

49354941
if (!format_len) {
49364942
return ZSTR_EMPTY_ALLOC();
@@ -4939,41 +4945,40 @@ static zend_string *date_interval_format(const char *format, size_t format_len,
49394945
for (i = 0; i < format_len; i++) {
49404946
if (have_format_spec) {
49414947
switch (format[i]) {
4942-
case 'Y': length = slprintf(buffer, sizeof(buffer), "%02d", (int) t->y); break;
4943-
case 'y': length = slprintf(buffer, sizeof(buffer), "%d", (int) t->y); break;
4948+
case 'Y': smart_str_append_printf(&string, "%02d", (int) t->y); break;
4949+
case 'y': smart_str_append_long_outline(&string, (int) t->y); break;
49444950

4945-
case 'M': length = slprintf(buffer, sizeof(buffer), "%02d", (int) t->m); break;
4946-
case 'm': length = slprintf(buffer, sizeof(buffer), "%d", (int) t->m); break;
4951+
case 'M': smart_str_append_printf(&string, "%02d", (int) t->m); break;
4952+
case 'm': smart_str_append_long_outline(&string, (int) t->m); break;
49474953

4948-
case 'D': length = slprintf(buffer, sizeof(buffer), "%02d", (int) t->d); break;
4949-
case 'd': length = slprintf(buffer, sizeof(buffer), "%d", (int) t->d); break;
4954+
case 'D': smart_str_append_printf(&string, "%02d", (int) t->d); break;
4955+
case 'd': smart_str_append_long_outline(&string, (int) t->d); break;
49504956

4951-
case 'H': length = slprintf(buffer, sizeof(buffer), "%02d", (int) t->h); break;
4952-
case 'h': length = slprintf(buffer, sizeof(buffer), "%d", (int) t->h); break;
4957+
case 'H': smart_str_append_printf(&string, "%02d", (int) t->h); break;
4958+
case 'h': smart_str_append_long_outline(&string, (int) t->h); break;
49534959

4954-
case 'I': length = slprintf(buffer, sizeof(buffer), "%02d", (int) t->i); break;
4955-
case 'i': length = slprintf(buffer, sizeof(buffer), "%d", (int) t->i); break;
4960+
case 'I': smart_str_append_printf(&string, "%02d", (int) t->i); break;
4961+
case 'i': smart_str_append_long_outline(&string, (int) t->i); break;
49564962

4957-
case 'S': length = slprintf(buffer, sizeof(buffer), "%02" ZEND_LONG_FMT_SPEC, (zend_long) t->s); break;
4958-
case 's': length = slprintf(buffer, sizeof(buffer), ZEND_LONG_FMT, (zend_long) t->s); break;
4963+
case 'S': smart_str_append_printf(&string, "%02" ZEND_LONG_FMT_SPEC, (zend_long) t->s); break;
4964+
case 's': smart_str_append_long_outline(&string, (zend_long) t->s); break;
49594965

4960-
case 'F': length = slprintf(buffer, sizeof(buffer), "%06" ZEND_LONG_FMT_SPEC, (zend_long) t->us); break;
4961-
case 'f': length = slprintf(buffer, sizeof(buffer), ZEND_LONG_FMT, (zend_long) t->us); break;
4966+
case 'F': smart_str_append_printf(&string, "%06" ZEND_LONG_FMT_SPEC, (zend_long) t->us); break;
4967+
case 'f': smart_str_append_long_outline(&string, (zend_long) t->us); break;
49624968

49634969
case 'a': {
49644970
if ((int) t->days != TIMELIB_UNSET) {
4965-
length = slprintf(buffer, sizeof(buffer), "%d", (int) t->days);
4971+
smart_str_append_long_outline(&string, (int) t->days);
49664972
} else {
4967-
length = slprintf(buffer, sizeof(buffer), "(unknown)");
4973+
smart_str_appends_outline(&string, "(unknown)");
49684974
}
49694975
} break;
4970-
case 'r': length = slprintf(buffer, sizeof(buffer), "%s", t->invert ? "-" : ""); break;
4971-
case 'R': length = slprintf(buffer, sizeof(buffer), "%c", t->invert ? '-' : '+'); break;
4976+
case 'r': if (t->invert) smart_str_appendc(&string, '-'); break;
4977+
case 'R': smart_str_appendc(&string, t->invert ? '-' : '+'); break;
49724978

4973-
case '%': length = slprintf(buffer, sizeof(buffer), "%%"); break;
4974-
default: buffer[0] = '%'; buffer[1] = format[i]; buffer[2] = '\0'; length = 2; break;
4979+
case '%': smart_str_appendc(&string, '%'); break;
4980+
default: smart_str_appendc(&string, '%'); smart_str_appendc(&string, format[i]); break;
49754981
}
4976-
smart_str_appendl(&string, buffer, length);
49774982
have_format_spec = 0;
49784983
} else {
49794984
if (format[i] == '%') {

0 commit comments

Comments
 (0)