Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add DateFormat function #18

Closed
wants to merge 1 commit into from

Conversation

@tpetry
Copy link
Owner

tpetry commented Oct 21, 2023

Just formatting nothing in some cases is against this package's idea as it is trying to harmonize a concept to work exactly with each database. There are two ways to solve the problem:

  1. Only the common formatting options are used
  2. Missing ones are emulated. The 2-year data for example could be emulated for example in PG by substring('1988' from 3).

@MohannadNaj MohannadNaj marked this pull request as draft October 25, 2023 01:14
@MohannadNaj
Copy link
Contributor Author

MohannadNaj commented Oct 25, 2023

Hello @tpetry .. Just pushed some progress on this, 2. Missing ones are emulated., but I'm not really confident about the implementation; your feedback for what's done so far is appreciated 🙏

  • I'm considering adding a test with a hard-coded date, to test the SQL output and not just the generated statements.
  • Now, I'll continue adding emulated characters, and remove the "format nothing or fallback to something else" characters

@tpetry
Copy link
Owner

tpetry commented Oct 25, 2023

I am not confident either. At the moment I've built all expressions based on the concept that I know how the implementations behave for every database. But with the date formatting that is much more complicated. Either I would have to manually test all these placeholder to check whether they match the theory. Or further extend the testing logic to also check the result of the SQL query.

Is the table migration closure in the tests really needed? I guess all databases should have the datetime type.

Edit: The special snowflake SQLite again doesn't have this type. Maybe I should add the testing then to use the blueprint for all tests. I'll have to think about it.

@MohannadNaj
Copy link
Contributor Author

MohannadNaj commented Dec 2, 2023

Hello @tpetry,

Sorry for the time it took me to revisit my approach to this and share my updates.

Most of the characters are now supported (Full support table below). But the PR size has increased. It's totally understandable if you're having second thoughts about adding this functionality.

  1. The each character cumbersome:

A major change was moving away from pushing as many characters as possible to the date format function, to concat each character and only map one character at a time. This will result in a longer SQL statement, Y-m will be in SQL Server: (concat(FORMAT([created_at], 'yyyy'),'-',FORMAT([created_at], 'MM'),... instead of FORMAT([created_at], 'yyyy-MM')

Reasons for this: the DBMS behavior differs towards the additional non-format characters, or if the format ended with spaces or dashes or something else. Unfortunately, I've lost the exact test cases where I've noticed this issue. Also, after cleaning up from that approach, the code got simplified (Got to remove these lines) so I opted to keep it.

  1. The emulated queries contain (CASE WHEN.. among other DB function calls and calculations, let me know if you prefer building these queries inside a function instead of a property, so we can for example reuse the CaseGroup class -among many other benefits-.

  2. The emulated queries are in uppercase for everything except the outputs 'am', 'Sun',.., let me know if it's preferred to be lowercase.

  3. Possible issues:

  • the escape character \, Similar to the PHP date format function, \YY should return Y2023.
  • Timezone offset, easier to implement with the direct format characters, tricky for the emulated characters.
Support table
.. Format .. MySQL SQLite PostgreSQL SQL Server Full Support
dDay of the month, 2 digits with leading zeros (01 to 31)
%d %d DD dd
DA textual representation of a day, three letters (Mon through Sun)
%a
🔗️️(CASE WHEN STRFTIME('%%w', %s) = '0' THEN 'Sun' WHEN STRFTIME('%%w', %s) = '1' THEN 'Mon' WHEN STRFTIME('%%w', %s) = '2' THEN 'Tue' WHEN STRFTIME('%%w', %s) = '3' THEN 'Wed' WHEN STRFTIME('%%w', %s) = '4' THEN 'Thu' WHEN STRFTIME('%%w', %s) = '5' THEN 'Fri' WHEN STRFTIME('%%w', %s) = '6' THEN 'Sat' END)
Dy ddd
jDay of the month without leading zeros (1 to 31)
%e
🔗️️LTRIM(STRFTIME('%%d', %s), '0')
FMDD
🔗️️CAST(DAY(%s) AS VARCHAR(2))
lA full textual representation of the day of the week (Sunday through Saturday)
%W
🔗️️(CASE WHEN STRFTIME('%%w', %s) = '0' THEN 'Sunday' WHEN STRFTIME('%%w', %s) = '1' THEN 'Monday' WHEN STRFTIME('%%w', %s) = '2' THEN 'Tuesday' WHEN STRFTIME('%%w', %s) = '3' THEN 'Wednesday' WHEN STRFTIME('%%w', %s) = '4' THEN 'Thursday' WHEN STRFTIME('%%w', %s) = '5' THEN 'Friday' WHEN STRFTIME('%%w', %s) = '6' THEN 'Saturday' END)
🔗️️TRIM(TO_CHAR(%s, 'Day'))
🔗️️(CASE WHEN DATEPART(WEEKDAY, %s) = 1 THEN 'Sunday' WHEN DATEPART(WEEKDAY, %s) = 2 THEN 'Monday' WHEN DATEPART(WEEKDAY, %s) = 3 THEN 'Tuesday' WHEN DATEPART(WEEKDAY, %s) = 4 THEN 'Wednesday' WHEN DATEPART(WEEKDAY, %s) = 5 THEN 'Thursday' WHEN DATEPART(WEEKDAY, %s) = 6 THEN 'Friday' WHEN DATEPART(WEEKDAY, %s) = 7 THEN 'Saturday' END)
NISO 8601 numeric representation of the day of the week (1 for Monday through 7 for Sunday)
SEnglish ordinal suffix for the day of the month, 2 characters (st, nd, rd, or th)
wNumeric representation of the day of the week (0 for Sunday through 6 for Saturday)
🔗️️(DAYOFWEEK(%s) + 5) %% 7 + 1
🔗️️(STRFTIME('%%w', %s) + 6) %% 7 + 1
🔗️️EXTRACT(DOW FROM %s)::INTEGER
🔗️️(CAST(DATEPART(WEEKDAY, %s) AS VARCHAR(2)) + 5) %% 7 + 1
zThe day of the year (starting from 0) (0 through 365)
WISO 8601 week number of the year, weeks starting on Monday (Example: 42)
%v
🔗️️(STRFTIME('%%j', %s, 'weekday 0', '-3 days') - 1) / 7 + 1
IW
🔗️️CAST(DATEPART(ISO_WEEK, %s) AS VARCHAR(2))
FA full textual representation of a month (January through December)
%M
🔗️️(CASE WHEN STRFTIME('%%m', %s) = '01' THEN 'January' WHEN STRFTIME('%%m', %s) = '02' THEN 'February' WHEN STRFTIME('%%m', %s) = '03' THEN 'March' WHEN STRFTIME('%%m', %s) = '04' THEN 'April' WHEN STRFTIME('%%m', %s) = '05' THEN 'May' WHEN STRFTIME('%%m', %s) = '06' THEN 'June' WHEN STRFTIME('%%m', %s) = '07' THEN 'July' WHEN STRFTIME('%%m', %s) = '08' THEN 'August' WHEN STRFTIME('%%m', %s) = '09' THEN 'September' WHEN STRFTIME('%%m', %s) = '10' THEN 'October' WHEN STRFTIME('%%m', %s) = '11' THEN 'November' WHEN STRFTIME('%%m', %s) = '12' THEN 'December' END)
🔗️️TRIM(TO_CHAR(%s, 'Month'))
🔗️️(CASE WHEN MONTH(%s) = 1 THEN 'January' WHEN MONTH(%s) = 2 THEN 'February' WHEN MONTH(%s) = 3 THEN 'March' WHEN MONTH(%s) = 4 THEN 'April' WHEN MONTH(%s) = 5 THEN 'May' WHEN MONTH(%s) = 6 THEN 'June' WHEN MONTH(%s) = 7 THEN 'July' WHEN MONTH(%s) = 8 THEN 'August' WHEN MONTH(%s) = 9 THEN 'September' WHEN MONTH(%s) = 10 THEN 'October' WHEN MONTH(%s) = 11 THEN 'November' WHEN MONTH(%s) = 12 THEN 'December' END)
mNumeric representation of a month, with leading zeros (01 through 12)
%m %m MM MM
MA short textual representation of a month, three letters (Jan through Dec)
%b
🔗️️(CASE WHEN STRFTIME('%%m', %s) = '01' THEN 'Jan' WHEN STRFTIME('%%m', %s) = '02' THEN 'Feb' WHEN STRFTIME('%%m', %s) = '03' THEN 'Mar' WHEN STRFTIME('%%m', %s) = '04' THEN 'Apr' WHEN STRFTIME('%%m', %s) = '05' THEN 'May' WHEN STRFTIME('%%m', %s) = '06' THEN 'Jun' WHEN STRFTIME('%%m', %s) = '07' THEN 'Jul' WHEN STRFTIME('%%m', %s) = '08' THEN 'Aug' WHEN STRFTIME('%%m', %s) = '09' THEN 'Sep' WHEN STRFTIME('%%m', %s) = '10' THEN 'Oct' WHEN STRFTIME('%%m', %s) = '11' THEN 'Nov' WHEN STRFTIME('%%m', %s) = '12' THEN 'Dec' END)
Mon
🔗️️(CASE WHEN MONTH(%s) = 1 THEN 'Jan' WHEN MONTH(%s) = 2 THEN 'Feb' WHEN MONTH(%s) = 3 THEN 'Mar' WHEN MONTH(%s) = 4 THEN 'Apr' WHEN MONTH(%s) = 5 THEN 'May' WHEN MONTH(%s) = 6 THEN 'Jun' WHEN MONTH(%s) = 7 THEN 'Jul' WHEN MONTH(%s) = 8 THEN 'Aug' WHEN MONTH(%s) = 9 THEN 'Sep' WHEN MONTH(%s) = 10 THEN 'Oct' WHEN MONTH(%s) = 11 THEN 'Nov' WHEN MONTH(%s) = 12 THEN 'Dec' END)
nNumeric representation of a month, without leading zeros (1 through 12)
%c
🔗️️LTRIM(STRFTIME('%%m', %s), '0')
FMMM
🔗️️CAST(MONTH(%s) AS VARCHAR(2))
tNumber of days in the given month (28 through 31)
🔗️️DAY(LAST_DAY(%s))
🔗️️STRFTIME('%%d', DATE(%s, '+1 month', 'start of month', '-1 day'))
🔗️️EXTRACT(DAY FROM DATE_TRUNC('month', %s) + INTERVAL '1 month - 1 day')::INTEGER
🔗️️CAST(DAY(EOMONTH(%s)) AS VARCHAR(2))
LWhether it's a leap year (1 if it is a leap year, 0 otherwise)
oISO 8601 week-numbering year (Examples: 1999 or 2003)
%x
🔗️️(CASE WHEN STRFTIME('%%m', %s) = '01' AND STRFTIME('%%d', %s) <= '03' THEN STRFTIME('%%Y', %s) - 1 ELSE STRFTIME('%%Y', %s) END)
🔗️️(CASE WHEN EXTRACT(MONTH FROM %s)::INTEGER = 1 AND EXTRACT(DAY FROM %s)::INTEGER <= 3 THEN EXTRACT(YEAR FROM %s)::INTEGER - 1 ELSE EXTRACT(YEAR FROM %s)::INTEGER END)
🔗️️(CASE WHEN MONTH(%s) = 1 AND DAY(%s) <= 3 THEN YEAR(%s) - 1 ELSE YEAR(%s) END)
XAn expanded full numeric representation of a year, at least 4 digits, with - for years BCE, and + for years CE (Examples: -0055, +0787, +1999, +10191)
xAn expanded full numeric representation if required, or a standard full numeral representation if possible (like Y). At least four digits. Years BCE are prefixed with a -. Years beyond (and including) 10000 are prefixed by a + (Examples: -0055, 0787, 1999, +10191)
YA full numeric representation of a year, at least 4 digits, with - for years BCE (Examples: -0055, 0787, 1999, 2003, 10191)
%Y %Y YYYY yyyy
yA two-digit representation of a year (Examples: 99 or 03)
%y
🔗️️SUBSTR(STRFTIME('%%Y', %s), 3, 2)
YY
🔗️️RIGHT(CAST(YEAR(%s) AS VARCHAR(4)), 2)
aLowercase Ante meridiem and Post meridiem (am or pm)
🔗️️(CASE WHEN hour(%s) < 12 THEN 'am' ELSE 'pm' END)
🔗️️(CASE WHEN STRFTIME('%%H', %s) < '12' THEN 'am' ELSE 'pm' END)
🔗️️(CASE WHEN EXTRACT(HOUR FROM %s)::INTEGER < 12 THEN 'am' ELSE 'pm' END)
🔗️️(CASE WHEN FORMAT(%s, 'tt') = 'am' THEN 'am' ELSE 'pm' END)
AUppercase Ante meridiem and Post meridiem (AM or PM)
%p
🔗️️(CASE WHEN STRFTIME('%%H', %s) < '12' THEN 'AM' ELSE 'PM' END)
AM tt
BSwatch Internet time (000 through 999)
g12-hour format of an hour without leading zeros (1 through 12)
🔗️️HOUR(%s) %% 12
🔗️️(CASE WHEN STRFTIME('%%H', %s) > '12' THEN LTRIM(STRFTIME('%%H', %s) - 12, '0') ELSE LTRIM(STRFTIME('%%H', %s), '0') END)
🔗️️(EXTRACT(HOUR FROM %s)::INTEGER %% 12)
🔗️️(CAST(DATEPART(HOUR, %s) AS VARCHAR(2)) %% 12)
G24-hour format of an hour without leading zeros (0 through 23)
🔗️️HOUR(%s)
🔗️️LTRIM(STRFTIME('%%H', %s), '0')
🔗️️CAST(EXTRACT(HOUR FROM %s)::INTEGER AS VARCHAR(2))
🔗️️CAST(DATEPART(HOUR, %s) AS VARCHAR(2))
h12-hour format of an hour with leading zeros (01 through 12)
%h
🔗️️(CASE WHEN STRFTIME('%%H', %s) > '12' THEN STRFTIME('%%H', %s) - 12 ELSE STRFTIME('%%H', %s) END)
HH12 hh
H24-hour format of an hour with leading zeros (00 through 23)
%H %H HH24 HH
iMinutes with leading zeros (00 to 59)
%i %M MI mm
sSeconds with leading zeros (00 through 59)
%s %S SS ss
uMicroseconds (Note: date() will always generate 000000 since it takes an int parameter, whereas DateTime::format() does support microseconds if DateTime was created with microseconds. Example: 654321)
vMilliseconds (Same note applies as for u. Example: 654)
eTimezone identifier (Examples: UTC, GMT, Atlantic/Azores)
IWhether or not the date is in daylight saving time (1 if Daylight Saving Time, 0 otherwise)
ODifference to Greenwich time (GMT) without colon between hours and minutes (Example: +0200)
PDifference to Greenwich time (GMT) with colon between hours and minutes (Example: +02:00)
pThe same as P, but returns Z instead of +00:00 (available as of PHP 8.0.0. Examples: Z or +02:00)
TTimezone abbreviation, if known; otherwise, the GMT offset (Examples: EST, MDT, +05)
ZTimezone offset in seconds (The offset for timezones west of UTC is always negative, and for those east of UTC is always positive. -43200 through 50400)
cISO 8601 date (2004-02-12T15:19:21+00:00)
rRFC 2822/RFC 5322 formatted date (Example: Thu, 21 Dec 2000 16:01:07 +0200)
USeconds since the Unix Epoch (January 1, 1970, 00:00:00 GMT, See also time())
🔗️️UNIX_TIMESTAMP(%s)
%s
🔗️️EXTRACT(EPOCH FROM %s)::INTEGER
🔗️️DATEDIFF(SECOND, '1970-01-01', %s)
script to generate the table
#!/usr/bin/env php
<?php

require __DIR__.'/../vendor/autoload.php';

use Tpetry\QueryExpressions\Function\Date\DateFormat;

$dateFormats = [
    'd' => 'Day of the month, 2 digits with leading zeros (01 to 31)',
    'D' => 'A textual representation of a day, three letters (Mon through Sun)',
    'j' => 'Day of the month without leading zeros (1 to 31)',
    'l' => 'A full textual representation of the day of the week (Sunday through Saturday)',
    'N' => 'ISO 8601 numeric representation of the day of the week (1 for Monday through 7 for Sunday)',
    'S' => 'English ordinal suffix for the day of the month, 2 characters (st, nd, rd, or th)',
    'w' => 'Numeric representation of the day of the week (0 for Sunday through 6 for Saturday)',
    'z' => 'The day of the year (starting from 0) (0 through 365)',
    'W' => 'ISO 8601 week number of the year, weeks starting on Monday (Example: 42)',
    'F' => 'A full textual representation of a month (January through December)',
    'm' => 'Numeric representation of a month, with leading zeros (01 through 12)',
    'M' => 'A short textual representation of a month, three letters (Jan through Dec)',
    'n' => 'Numeric representation of a month, without leading zeros (1 through 12)',
    't' => 'Number of days in the given month (28 through 31)',
    'L' => 'Whether it\'s a leap year (1 if it is a leap year, 0 otherwise)',
    'o' => 'ISO 8601 week-numbering year (Examples: 1999 or 2003)',
    'X' => 'An expanded full numeric representation of a year, at least 4 digits, with - for years BCE, and + for years CE (Examples: -0055, +0787, +1999, +10191)',
    'x' => 'An expanded full numeric representation if required, or a standard full numeral representation if possible (like Y). At least four digits. Years BCE are prefixed with a -. Years beyond (and including) 10000 are prefixed by a + (Examples: -0055, 0787, 1999, +10191)',
    'Y' => 'A full numeric representation of a year, at least 4 digits, with - for years BCE (Examples: -0055, 0787, 1999, 2003, 10191)',
    'y' => 'A two-digit representation of a year (Examples: 99 or 03)',
    'a' => 'Lowercase Ante meridiem and Post meridiem (am or pm)',
    'A' => 'Uppercase Ante meridiem and Post meridiem (AM or PM)',
    'B' => 'Swatch Internet time (000 through 999)',
    'g' => '12-hour format of an hour without leading zeros (1 through 12)',
    'G' => '24-hour format of an hour without leading zeros (0 through 23)',
    'h' => '12-hour format of an hour with leading zeros (01 through 12)',
    'H' => '24-hour format of an hour with leading zeros (00 through 23)',
    'i' => 'Minutes with leading zeros (00 to 59)',
    's' => 'Seconds with leading zeros (00 through 59)',
    'u' => 'Microseconds (Note: date() will always generate 000000 since it takes an int parameter, whereas DateTime::format() does support microseconds if DateTime was created with microseconds. Example: 654321)',
    'v' => 'Milliseconds (Same note applies as for u. Example: 654)',
    'e' => 'Timezone identifier (Examples: UTC, GMT, Atlantic/Azores)',
    'I' => 'Whether or not the date is in daylight saving time (1 if Daylight Saving Time, 0 otherwise)',
    'O' => 'Difference to Greenwich time (GMT) without colon between hours and minutes (Example: +0200)',
    'P' => 'Difference to Greenwich time (GMT) with colon between hours and minutes (Example: +02:00)',
    'p' => 'The same as P, but returns Z instead of +00:00 (available as of PHP 8.0.0. Examples: Z or +02:00)',
    'T' => 'Timezone abbreviation, if known; otherwise, the GMT offset (Examples: EST, MDT, +05)',
    'Z' => 'Timezone offset in seconds (The offset for timezones west of UTC is always negative, and for those east of UTC is always positive. -43200 through 50400)',
    'c' => 'ISO 8601 date (2004-02-12T15:19:21+00:00)',
    'r' => 'RFC 2822/RFC 5322 formatted date (Example: Thu, 21 Dec 2000 16:01:07 +0200)',
    'U' => 'Seconds since the Unix Epoch (January 1, 1970, 00:00:00 GMT, See also time())',
];

$output = "| .. Format .. | MySQL | SQLite | PostgreSQL | SQL Server | Full Support |\n";
$output .= "| --- | --- | --- | --- | --- | --- |\n";

$class = new ReflectionClass(DateFormat::class);
$emulatableCharacters = $class->getDefaultProperties()['emulatableCharacters'];
$formatCharacters = $class->getDefaultProperties()['formatCharacters'];

foreach ($dateFormats as $character => $description) {
    $output .= "| <details><summary>`{$character}`</summary>{$description}</details> | ";

    $fullSupport = true;

    foreach (['mysql', 'sqlite', 'pgsql', 'sqlsrv'] as $driver) {
        $format = $formatCharacters[$driver][$character] ?? null;
        $emulatableCharacter = $emulatableCharacters[$driver][$character] ?? null;

        if ($format) {
            $output .= "`$format`";
        } elseif ($emulatableCharacter) {
            $output .= "<details><summary>🔗️️</summary>`$emulatableCharacter`</details>";
        } else {
            $output .= '';
            $fullSupport = false;
        }

        $output .= ' | ';
    }

    $output .= $fullSupport ? '' : '';
    $output .= "\n";
}

echo $output;

@tpetry
Copy link
Owner

tpetry commented Dec 4, 2023

Thanks for the big PR. But I'll need quite some time to go through it completely. Shouldn't we throw exceptions when unsupported date formats are used?

@tpetry tpetry marked this pull request as ready for review December 4, 2023 09:07
@tpetry
Copy link
Owner

tpetry commented Dec 28, 2023

@MohannadNaj You're still working on the date format functionality in your fork. So is this code still a draft as you have new ideas to further improve it?

@MohannadNaj MohannadNaj marked this pull request as draft December 29, 2023 16:10
@MohannadNaj
Copy link
Contributor Author

MohannadNaj commented Dec 29, 2023

@tpetry Yes, some changes are still in progress in another branch here. I also prefer to close this PR and re-submit in a new PR when it's ready.

It's another branch because I'm not sure if you agree with the approach I'm taking in it (Mainly, reusing expressions in the emulated queries), will make it into this branch after your initial feedback. (Thanks in advance 🙏).


Done:

  1. Better organization of the code (Different traits for Direct and Emulated characters and the main class for the core logic only).
  2. Handling escaped characters.

Done but needs your approval/comment:

  1. Reusing expressions in emulated queries instead of always returning the SQL string.

For example instead of Sqlite's A emulated query:

- 'A' => '(CASE WHEN STRFTIME(\'%%H\', %s) < \'12\' THEN \'AM\' ELSE \'PM\' END)',
+ 'A' => (new CaseGroup(
+     when: [
+         new CaseRule(
+             new Value('AM'),
+             new LessThan(
+                 new QueryExpression('STRFTIME(\'%%H\', %s)'),
+                 new Value('12'),
+             )
+         ),
+     ],
+     else: new Value('PM'),
+ )),

Do we want this? it's resulting in a larger code base (Current EmulatedDateFormat trait is +480 lines).. It's possible to just revert it to a long array with the direct SQL string, but reusing the package expressions feels cleaner/safer.

  1. Not directly related to this PR, but while doing the previous points I found myself needing to create Ltrim class, let me know if it should be submitted in a new PR -and if so, should I add Rtrim and Trim as well?-.

Still wip:

  1. Handling unsupported characters.

Shouldn't we throw exceptions when unsupported date formats are used?

Yes I agree.

  1. Localizable values: Currently we are returning directly the english names only Sunday,..etc, For now I just want to ensure there is a way to change these values, for example by something like DateFormat::mergeLocal(['days_full' => [0 => Sunday,...]]). What do you think?

@tpetry
Copy link
Owner

tpetry commented Dec 31, 2023

  1. Reusing expressions in emulated queries instead of always returning the SQL string.

For example instead of Sqlite's A emulated query:

- 'A' => '(CASE WHEN STRFTIME(\'%%H\', %s) < \'12\' THEN \'AM\' ELSE \'PM\' END)',
+ 'A' => (new CaseGroup(
+     when: [
+         new CaseRule(
+             new Value('AM'),
+             new LessThan(
+                 new QueryExpression('STRFTIME(\'%%H\', %s)'),
+                 new Value('12'),
+             )
+         ),
+     ],
+     else: new Value('PM'),
+ )),

Do we want this? it's resulting in a larger code base (Current EmulatedDateFormat trait is +480 lines).. It's possible to just revert it to a long array with the direct SQL string, but reusing the package expressions feels cleaner/safer.

I am still unsure about this approach. I see a problem that all test cases are failing when dependent expressions are changed. I think I prefer not building expressions on-top of others because of this.

  1. Not directly related to this PR, but while doing the previous points I found myself needing to create Ltrim class, let me know if it should be submitted in a new PR -and if so, should I add Rtrim and Trim as well?-.

A Trim expressions sounds good. First param could be the column/expression and second param optionally the mode to use - defaulting to trimming on both sides.

  1. Localizable values: Currently we are returning directly the english names only Sunday,..etc, For now I just want to ensure there is a way to change these values, for example by something like DateFormat::mergeLocal(['days_full' => [0 => Sunday,...]]). What do you think?

Yeah, localization is a big problem. I haven't yet tested all the different databases. Could we provide a language to use for the expression? Or could it just be the task for the user to set the appropriate language within the database connection?

@MohannadNaj
Copy link
Contributor Author

Closing for a re-submission in another PR.


Localizable values: Currently we are returning directly the english names only Sunday,..etc, For now I just want to ensure there is a way to change these values, for example by something like DateFormat::mergeLocal(['days_full' => [0 => Sunday,...]]). What do you think?

Yeah, localization is a big problem. I haven't yet tested all the different databases. Could we provide a language to use for the expression? Or could it just be the task for the user to set the appropriate language within the database connection?

I've used Carbon's default locale to produce the textual formats, this way we won't have to maintain these values, which turned out to be only used by our dear SQLite lol, other DBMSs have a built-in way of producing such formats.

If the user uses SQLite and wants a different locale, that should happen by Carbon\Carbon::setLocale('xx'), for other databases this is a database-level configuration (for MySQL, that would be changing the value of the session/global variable lc_time_names).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants