Open solodkiy opened 6 years ago
Hi, this is not yet implemented in the library itself. I'm using a DateTimeFormatter class in my projects for this purpose.
It's based on intl and therefore accepts a locale rather than a 'd.m.y' string.
It's not yet merged into the library because there are several ways to format a given date or time even for a single locale, and this class allows only one. Examples in fr_FR
:
Date:
Time:
And for date/time, a combination of those (6 possibilities at least). So the only thing to do to implement the formatter in the library is to find a clean API for these settings.
BTW, do you have a special requirement for setting explicitly the date/time format like d.m.y
, or would the locale-based format be OK for you?
I really need setting explicitly the date/time format like d.m.y because I can't control formats what other services expecting from me. For me parse and print date/time from custom formats is must have functionality.
Some update: there is still no built-in way to parse and format from a format string just like PHP does; however, there are now methods to convert objects to and from native DateTime
objects:
fromDateTime()
toDateTime()
These methods are available in version 0.1.7 in the following classes:
LocalDate
LocalTime
LocalDateTime
ZonedDateTime
Although this is suboptimal, you can use these methods to achieve what you want, in the meantime:
$localDate = LocalDate::of(2017, 10, 18);
echo $localDate->toDateTime()->format('d/m/y'); // 18/10/17
Hello there. We faced a similar issue at work, so let me throw in my two cents:
Common task is convert date for human readability format
A common task indeed!
So the only thing to do to implement the formatter in the library is to find a clean API for these settings.
Why not draw again from the apparent source of inspiration for this library? The API of Java's DateTimeFormatter
closely resembles the parsing mechanism that's already implemented here (obviously so, because Java uses the very same class for both parsing and formatting) – couldn't the formatting API be ported in a similar way?
Just a concept of what the API might look like, sans builders and other utilities:
$localDate = LocalDate::of(2018, 11, 6);
$localDate->format(IsoFormatters::localDate()); // 2018-11-06
$localDate->format(PatternFormatter::of('d. M. yyyy')); // 6. 11. 2018
$localDate->format(LocalizedFormatter::ofDate('fr_FR', LocalizedFormatter::SHORT)) // 06/11/18
It looks versatile enough while still allowing for a certain level of strictness, and it's already somewhat proven by Java users. What do you think about such API?
I'm definitely in favour of adding a formatting API.
I think we should start with the easiest part IMO, which is what the OP requested: a custom formatter that accepts strings such as d. M. yyyy
.
The locale-based formatter is more obscure regarding possible formats, and I think we should discuss it in a separate thread.
The only thing we need, is to define the alphabet used for formatting. One idea would be to mimic PHP's date() alphabet, but we'll have to modify it somehow for things like nanos, which have no equivalent in PHP.
Another approach, which I'd favour as this project was inspired by Java indeed, is to use their alphabet instead (or a subset of it, at least: we don't implement "era" for example). They have a different approach from PHP, which is that a single letter can have several outputs depending on its repetition:
Format | PHP | Java |
---|---|---|
2018-02-01 | Y-m-d | yyyy-MM-dd |
1/2/18 | j/n/y | d/M/yy |
I quite like their approach. What do you think?
I like Java approach too, but mixing notations seems to me like a bad idea. This is PHP library, so I think it should take PHP notation about date.
The locale-based formatter is more obscure regarding possible formats
That, I believe, both is and isn't true. Let me just bring a related thought to light: In Java, some symbols in the pattern formatter such as DOW or month names are also locale-based. I'll elaborate below.
Another approach is to use their [Java's] alphabet instead
I like it more, too. I find the use of repetition much more obvious, as in d
vs dd
, as opposed to PHP's j
vs d
. The point about inconsistency with date() is sound, but the Java's alphabet is so much better grounded in standards; in fact, it uses a SimpleDateFormat as defined by the ICU. Getting back to the previous point about locale-based formatter, the very same ICU document also describes the SHORT, MEDIUM, LONG and FULL formats of localised dates and times, as used by what I call the LocalizedFormatter
in the API concept in my previous comment.
With the ICU format syntax – which can be used quite easily in PHP with the intl extension – the pattern-based formatter would be able to deal with the localised format obscurities on its own, and the LocalizedFormatter
could be kept for convenient usage of the pre-defined formats. At least that's how Java uses it afaik.
There are, of course, drawbacks. For example the "era", while not implemented, is supported in the format syntax and the PHP's intl extension formats it correctly, so there would be inconsistencies. Also, implementation-wise, using IntlDateFormatter and DateTimes for formatting might throw away the benefits of the abstraction, bringing in problems such as how to detect when a HH:mm:ss
formatter is used to format a LocalDate (which should throw an exception).
So yes, maybe a subset of the alphabet and some more custom implementation will be necessary, but in general, this is the direction that makes sense to me for the formatting API to take.
My vote for php-notation. Easy to implement (without any extensions), known by all php programmers.
Ok. Moving forward. This is quite unrelated from this issue, but also connected. We talk about date representation.
I have ZonedDateTime in some timezone (perhaps UTC, perhaps not) and I need to write it in xlsx report in Moscow timezone in some date format.
Convert to LocaTime in some point seems logical. What can I do right now?
$zonedDate->withTimeZoneSameInstant(TimeZone::parse('Europe/Moscow'))->getDateTime()->toDateTimeImmutable()->format('Y-m-d H:i:s');
Looks quite monstrous.
What I am looking for:
$zonedDate->getDateTime(TimeZone::parse('Europe/Moscow'))->format('Y-m-d H:i:s');
suggestion that getDateTime can convert zonned date to given time zone.
Or even $zonedDate->format('Y-m-d H:i:s', TimeZone::parse('Europe/Moscow'));
@BenMorel are you ok with adding optional TimeZone argument to Zoned getDateTime, getDate and getTime methods?
@solodkiy I don't see the point, I'm sorry? It sounds more logical to convert the ZonedDateTime to the timezone you want, then format as appropriate?
Another one possible approach - create classes which formats dates when converting object to string.
final class Rfc3339FormatZonedDateTime
{
private ZonedDateTime $dateTime;
public function __constructor(ZonedDateTime $dateTime)
{
$this->dateTime = $dateTime;
}
public function __toString(): string
{
// Make formatting logic here and return it
}
}
Then API of the main classes wouldn't be affected and we will be able to introduce set of default formatters and developer will be able to create new formats for their needs.
Common task is convert date for human readability format, or some special format like 'd.m.y' and I don't see how I can do this with this class. Did I miss some formatter class or this behavior don't implemented?