Currently Drupal core doesn't provide much help for date handling, nor even a date field. I've been working on a collection of patches that could make Drupal's core date handling much more robust, provide better ways for contrib modules to extend it, and hopefully lead to a date field in core.
This is the first patch I'd like to propose. This is the basis for everything else I hope we can do.
PHP has had a DateTime class since PHP 5.2. Prior to that it had only some pretty anemic date() and time() functions. The DateTime class is better for lots of reasons. It can accept various kinds of strings and create dates from them, like '10AM today', using functionality similar to the PHP strtotime() function. It is smart about timezone handling. The date() functions have no way to control timezone, but the DateTime class lets you specify it. At the moment, Drupal core uses the DateTime class in just a couple of places, but mostly ignores it.
That class, however, is still lacking a number of things that would make it more useful. It has a format() function, but that function can only create English date strings. It has no way to create a date from an array of date values, which would be very useful in form handling. It doesn't have a __toString() method. It is very lenient about interpreting dates, too lenient if you want to do validation of date inputs. For instance, it will take a date like '2/31/2012' and instead of treating that as an invalid date, it will turn it into '3/2/2012'.
Formatting date output is another issue. Drupal provides translation of formatted output in the format_date() class, but that still has some limitations. There is a new PHP class called the IntlDateFormatter that allows you to specify locales and calendars for much better international date handling. Unfortunately, although that is available by default from 5.3 on, it is not enabled by default, and it seems to be unavailable in lots of fairly ordinary places. OSX doesn't have it enable, for instance. But it would be nice for sites that do have that class available to be able to use it, while still providing some sort of fallback for sites that don't.
We have a custom extension of the DateTime object that we've been using in the Date API to fix some of those problems. I've done a lot of work to clean it up and improve it for D8, and I'd like to propose adding it to core in D8.
The patch actually creates two classes. First there is the DateObject class, which is direct extension of the DateTime class. It adds in the ability to accept various kinds of input values -- a string with an unknown format (the default behavior), a string with a known format (useful to make sure the date will be interpreted as intended since the parse can make mistakes about things like negative years), an array of date parts (useful for form handling), a timestamp, or another Date object.
The class incorporates a way to use the IntlDateFormatter for the format() method, if desired, and otherwise falls back to using the normal format() method. It also tightens up the leniency of the created dates so we can more easily validate the input.
The second class in this patch is an extension of the DateObject class to create a DrupalDate class. This basically extends the DateObject to tie it into Drupal's translation system. I've separated them into two classes since the main class could be useful outside of Drupal, and the second one is Drupal-specific. Then in Drupal we would use the DrupalDate class everywhere.
I have a follow up patch for this one that then changes format_date() to include the same settings array so users could optionally pass in the information needed by the IntlDateFormatter. Then instead of formatting the date in the previous way, it passes that settings array on to the date object so it can use the new format() functionality. I'll post that patch as a separate issue if this one is accepted.
I haven't included in this patch any other changes to core to use these classes, but that can be another follow up patch.
I hope patch will accomplish several things:
- Provide a robust way of handling dates that can be further extended in contrib.
- Provide a basis for doing better date form handling, both in core and in contrib.
- Provide part of the foundation needed to get a date field into core.
So here's my patch.
Comment | File | Size | Author |
---|---|---|---|
#104 | 1802278-104-date-component.patch | 64.92 KB | Lars Toomre |
#104 | interdiff-1802278-97-104.txt | 47.27 KB | Lars Toomre |
#97 | 1802278-date-component-97.patch | 63.14 KB | KarenS |
#97 | interdiff.txt | 1.22 KB | KarenS |
#92 | 1802278-date-component-92.patch | 63.08 KB | KarenS |
Comments
Comment #1
arlinsandbulte CreditAttribution: arlinsandbulte commentedJust to make sure testbot is happy (so far).
Comment #2
KarenS CreditAttribution: KarenS commentedOops, had some typos in the php docs. Try again.
Comment #3
andypostHere's a related #51043: Add a "datetime" Form API element
Comment #4
moshe weitzman CreditAttribution: moshe weitzman commentedNice!
Comment #5
KarenS CreditAttribution: KarenS commentedIt doesn't add a variable, it uses a core variable that hasn't been converted yet. I can add in the conversion of format_date to use this, but that adds a bunch of code.
Comment #6
Lars Toomre CreditAttribution: Lars Toomre commentedI am very glad to see this proposal and agree with #4.2 that one implementation would help make acceptance easier.
Comment #7
KarenS CreditAttribution: KarenS commentedOK, I'll work up a patch that has an implementation and post it soon.
Comment #8
KarenS CreditAttribution: KarenS commentedOK, new patch with implementations. The object allows us to simplify the TypedData date type and format_date(). It also provides the error handling required by things like the node form date validation.
Comment #10
mgiffordThere's a thread here about accessibility for date formats:
http://groups.drupal.org/node/19118
Also a number of existing issues for the date module (not sure if any code is reused, but still useful to consider):
http://drupal.org/project/issues/date?text=accessibility&status=All&prio...
Other related issues:
#1638078: [meta] Simplify complex form elements where possible
#1168246: Freedom For Fieldsets! Long Live The DETAILS.
The last patch looks like it almost got in, save:
Undefined property: Drupal\node\Node::$date
Comment #11
KarenS CreditAttribution: KarenS commentedI don't think there are any accessibility considerations with this, it is just the api for creating dates. As far as I can tell, all the linked issues are specific to implementation of the object in a date field, which is not what this patch is for. When we start creating date fields with this object we need to look at those. This is the raw object only, and some usage of that in core.
I don't have time right now to fix the broken test, but can try to do that later.
Comment #12
andypostFirst review:
1) Exception handling seems needs discussions
2) Locale and $langcode - not sure I understand a difference but please clarify
3) A few minor code-style related issues
It seems that $locale is a different thing then $langcode all over core now. Is it possible to specify difference somewhere?
Maybe Gregorian should be set by default in case emty parameter?
space needed after $system_timezone
Why do not use t() here or just named exception?
Not sure it's a good idea to use t() this way
Comment #13
andypostFixed broken test and moved DrupalDate.php to Core/Component
Comment #14
sun"DrupalDate" is not compatible with Drupal\Component. Make sure to read the Drupal\Component\README.txt.
You probably want a
Drupal\Core\Datetime\Date
that extendsDrupal\Component\Datetime\Date
.Note that I intentionally removed "Object". In case "Date" is a reserved keyword, then I'd suggest to use "DateTime", which might be cleaner anyway as it self-documents what this class is about and what it extends from; i.e.:
Comment #15
andypost@sun DateTime is reserved class name that we extending, so better do not use same names to avoid collisions with php namespace. Can we agree on current common practice to add 'Base' suffix:
EDIT I think better proceed with DateTimeBase and DrupalDateTime
Comment #16
webchickLet's please not add "Drupal" to any class name, if we can help it; it's already implied. :)
Comment #17
webchickHm. While what I said in #16 is generally true (see http://drupal.org/node/608152), andypost explained that what we're doing here is very similar to what we do in drupal_strtolower and like functions, which is basically "native PHP thing but without all the suck." "DrupalDateTime" is similar; it's taking the native PHP DateTime class and including localization and proper error handling.
So, ignore me, and let's go with DrupalDateTime.
Comment #18
andypostPatch with rename:
DateObject => DateTimeBase
DrupalDate => DrupalDateTime
- I think it's better because it self-documenting purpose and parents
Also fix same minor code-style issues
Comment #19
Lars Toomre CreditAttribution: Lars Toomre commentedSmall nit... In this patch, $calendartype has been changed to $calendar_type.
Does it also make sense to do similar renaming for variables $datetype and $timetype so that there is consistency? I would think so from afar.
Comment #20
andypost@Lars I think better follow param names from intldateformatter
And make it $calendar all over
Comment #21
Lars Toomre CreditAttribution: Lars Toomre commentedUsing $calendar all over makes sense @andypost.
Would it also make sense to document somewhere why $datetype and $timetype were used instead of $date_type and $time_type? As I understand the Drupal coding conventions, $date_type is the preferred variable name, yet it is not being used in this patch.
I am simply trying to make sure that we are consistent when someone else in D9+ comes back to look at this code.
Comment #22
andypost@Lars it looks debatable because of #20, the IntlDateFormatter::create() parameters are $datatype and $timetype
So it looks strange if we pass $settings with our kind of parameters and then use PHP function with without underscore
Comment #23
andypostSo changed all local variables to use underscore
Suppose no reason to change them in $settings because they are mimic PHP's variable names
Comment #24
KarenS CreditAttribution: KarenS commentedI'm in agreement with most of these changes. I just want to clarify that the patch uses both $calendar and $calendar_type. The IntlDateFormatter has a 'calendar' argument, but it's not the name of the calendar, it's basically a boolean to indicate whether or not the Gregorian calendar is used. If you want to use a non-gregorian calendar, you include it in the $locale string.
But we need to get core ready for other kinds of calendar handling where you need to know the calendar name, and that boolean value is not useful to anything but the IntlDateFormatter. So I split this up so you can provide both the calendar name and the boolean setting for the IntlDateFormatter as separate values. Then I add some helpers that construct the locale that the IntlFormatter wants unless something else has been input. So the real world use case for most people would be to provide just a calendar name and a format string in the right format and the code will do everything else that that is needed for the IntlFormatter. In the meantime, we now have an accepted way to pass a calendar name into a date class, so contrib modules that want to do more things with alternate calendars can do so.
As I now explain it, I suppose we could not even ask for the calendar_type variable and just deduce it from the calendar name, which would get rid of one variable.
Comment #25
KarenS CreditAttribution: KarenS commentedAnd to the question about $locale and $langcode. $langcode is our familiar Drupal variable for the name of a language. In this case, $locale is a string required by the IntlDateFormatter. It will look like:
So it is composed of the language, the country, and optionally a calendar. We know the language using $langcode. We know the site country. If a calendar name is passed in, we can add that. So we can construct the locale if it is not provided. But someone may want to use some other value for the locale, so we have to retain a way for it to be passed in. This code should make it possible to do either.
It is even more confusing because we have our own Locale module. I don't know what else I can do to make it more clear what is going on, though.
Comment #26
KarenS CreditAttribution: KarenS commentedOne other question. If we call the component 'DateTimeBase', it makes sense from Drupal's perspective -- we are extending that to add our own translation system to it. But the idea behind making it a component is that it could be useful outside of Drupal. And for that purpose the name makes less sense. It sounds like a DateTime class with less functionality than the PHP class has, when it has more. It is more like 'DateTimeExtended'. For instance, I think Symfony could use this component. I see a number places in the Symfony code we include in core where it would make sense.
Comment #27
andypost@KarenS Thanx a lot for deep clarification!
About class naming we can get never-endless bikesheding as always but the main reason to get this in. Suppose we can rename the class after freeze.
I think patch ready except error handling translatoin, so pushing it into D8MI team
Comment #28
KarenS CreditAttribution: KarenS commentedI took a stab at making this more clear. I changed the name of the base class to DateTimePlus and removed the $locale setting and instead ask for $langcode and $country. Then we construct the local string from those values. That should remove some WTF.
Comment #30
KarenS CreditAttribution: KarenS commentedWrong patch.
Comment #31
KarenS CreditAttribution: KarenS commentedWrong patch again :(
Comment #32
KarenS CreditAttribution: KarenS commentedOK, finally, this should be the right patch. I tried an interdiff but it's not very readable since it is dropping all the old files and adding in the renamed ones.
Comment #33
andypost@KarenS You could use
git diff -M25%
to get interdiff for renamed files, so here interdiffComment #34
sunUpfront, I'm sorry for only commenting on the class name instead of doing a proper/in-depth review, but don't have time for that today. ;)
DateTimePlus sounds similarly odd like DateTimeBase. Is there any reason we can't simply name it DateTime? (as in #14)
Code that is using this class certainly wants to use the user-space extension instead of the native/core class, so I don't think there is any problematic ambiguity involved (and all code is still able to explicitly reference \DateTime anyway).
Comment #35
andypost@sun As I commented above having same class name could lead to unpredictable troubles for example when some code needs both classes. Also it's a common practice to give different name to overloaded class
Comment #36
KarenS CreditAttribution: KarenS commentedI'm not a fan of the idea of naming the extension using the same name as the parent. I don't know of any other place In Drupal that we've done that, or anywhere else this has been done, for that matter. The idea is that this is a component that will work anywhere, we can't make any assumptions about how the core class might be used along side it. For that matter, the Symfony code we include in Drupal is still using the php DateTime class, so there is some possible ambiguity just within the Drupal code if we use the same class name for both.
Comment #38
KarenS CreditAttribution: KarenS commentedOn the translation question, this is similar to the translation problems of timezone names. I think we can just provide a list of the phrases that need translation for the parser.
Comment #39
Gábor HojtsyWhat kind of values need translation here? Can you provide examples? It is not clear from the comments above.
Comment #40
andypostExamples of exceptions:
This could generate a exception but exception message would be in server's locale
This kind o fmessages we can translate but probably better to have own set on exceptions
The resulting exception message language is unpredictable
Comment #41
Gábor HojtsyIf its in the server's locale first and foremost, then although we cannot 100% say it is English, I think most servers are set up with English default locale, no? (Honestly have not seen many server consoles in Estonia or Japan, just guessing :).
Comment #42
andypostbecause we make no output of errors we should not translate then
this is really bad
And this places still should not use t()
Comment #43
Gábor HojtsyThe errors should be translated depending on where they go. If they go to watchdog/syslog, then they should be English as much as possible (despite we cannot affect the server locale). If they are displayed, then they should be translated to the display language needed. If it is displayed via the watchdog log later for example on screen, then it will be t()-ed then. It needs to be marked for the translation system though so it ends up localize.drupal.org. We do not have a marker outside of t()/format_plural() that you can use, but you can put t() strings at a no-op section (eg. in a method after a return, etc). Read #1542144: Mark strings as localizable/translatable (new t()-alike string function that isn't t(), only for potx) especially http://drupal.org/node/1542144#comment-5904790 for more background.
Comment #44
KarenS CreditAttribution: KarenS commentedThe base component knows nothing about translation, so it just creates an array of errors. The subclass is where they should get translated, if at all. We can provide a list of values wrapped in t() for the messages that need translation as a helper somewhere. We've done that before.
These classes do not display the errors or do anything with them directly. The display of the errors is up to whatever code calls this object. In many cases they will never be displayed. The errors are mostly for debugging and so you can count to see if there are any errors for validation handling. So we can also just remove the remaining t()s completely.
Comment #45
KarenS CreditAttribution: KarenS commentedWhat I meant to say is that if there is any potential need for translation of the error messages supplied directly by this code, we can create a list of those exact messages wrapped in t() so they show up in the string translation system.
Comment #46
andypost@KarenS so only #42 is needs to be fixed, I very dislike in_array() pattern here
Comment #47
KarenS CreditAttribution: KarenS commentedI don't understand what you mean by disliking the in_array() pattern. This is because PHP reports a date like 2012-02-30 as a warning but not an error, and we need to flag that as an error. I do that by looking for the warning and basically making it an error instead.
Comment #48
andypost@KarenS because this message depends on server's locale and could fail if one is different from English
Comment #49
andypostThere's a suggestion about exceptions #817160: Don't translate exceptions
Comment #50
KarenS CreditAttribution: KarenS commentedOK, I see. But we need to know if that warning was set somehow. Because it needs to be promoted to an error or we end up creating the wrong date with no warning that the created date does not match the entered one. Not sure how to handle that....
I think PHP's handling is wrong, but there is no automatic way to alter it. At the least the IntlDateFormatter has a setting for 'lenient', which wrongly defaults to lenient but can be changed.
Comment #51
andypostProbably this should be static:: let's get PHP 5.3 late static binding
Comment #52
KarenS CreditAttribution: KarenS commentedOK, figured out something I hope will work correctly. It looks like the warning I am looking for is consistently returned using a key of 11, so I check for that warning number instead of the warning text. To clarify what is going on, I added a constant that identifies the warning number. I also removed the t()s and changed self:: to static::.
Comment #53
hass CreditAttribution: hass commentedWe should add some tests for 24h timezones. I have not seen any test for an EU / German time like
16:00
=4:00 pm
and this could cause validators to fail.Comment #54
KarenS CreditAttribution: KarenS commentedIf you have specific use cases you'd like to test I'll be glad to add the tests. I can't really figure out what you want to test here. If possible I'd like to move additional test coverage into a follow up issue and get this committed. I have a bunch of other work I'd like to get in that is blocked until this lands.
Comment #55
cosmicdreams CreditAttribution: cosmicdreams commentedI'll take a shot at this test on Friday night.
Comment #56
KarenS CreditAttribution: KarenS commentedRerolling patch to catch up to head with a few changes:
- I added a bunch of additional timezone tests.
- I realized when I split out the new component that I didn't add back in a check for Drupal's site timezone or user timezone, so that is added to the DrupalDateTime class, and some tests to be sure this is working correctly.
The last change requires an explanation. There is one other type of timezone treatment that can be problematic when using the DateTime class. If you create a DateTime object using a string that contains either a timezone offset or timezone abbreviation, it will ignore any timezone name you try to supply and create a DateTime object with a timezone name of '+10:00' or 'EST'. Those values are ambiguous -- lots of timezones have the same offset or abbreviation. That means the resulting date can't really be relied on. The specific date you input may be correct, but if you try to use date_modify() it won't work right. Derick Rethans, the person behind most of the PHP DateTime functions, posted about this issue at http://derickrethans.nl/gmt-being-tricky.html. The best solution seems to be to see if the provided timezone name matches the offset or abbreviation passed in the string. If so, we can set the timezone name correctly. If not, we should flag this as an error. So I've added this functionality along with some tests for that.
Comment #58
renat CreditAttribution: renat commentedAnd if timezone was reformed? For example, in Russia there are no more Daylight Saving Time since 2011. What about such cases? As far as Date field represented dates in UTC internally, it was OK - but will it be for now?
Comment #59
renat CreditAttribution: renat commentedSorry.
Comment #60
KarenS CreditAttribution: KarenS commented@renat, please see if this is actually a problem before changing the status. PHP is doing all the internal handling of dates. Nothing in this code should be creating a problem. If you can demonstrate that this code breaks some logical method of creating dates, please provide an example.
Comment #61
KarenS CreditAttribution: KarenS commentedSorry, I see you didn't change the status, you just changed it back. But still, can you see if there is an actual problem?
Comment #62
KarenS CreditAttribution: KarenS commentedSo the test failures are for places in core that we are creating dates without real timezones, like '1969-01-01 00:00:00 -0500'. The tests are fixed if we quit doing that and change it to something like '1969-01-01 00:00:00 America/Chicago'. Which IMO would be preferable anyway. I don't know how people feel about that change, but I can make that change or go back to allowing the broken offset-only dates that can't be safely modified.
Comment #63
KarenS CreditAttribution: KarenS commentedAs to #58, I'm trying to understand the question. If you're asking if PHP understands that daylight savings time changed in Russia, it does, and there should be no problem. However it will only get daylight savings time right if you give it a fully qualified timezone name instead of an offset.
Comment #64
renat CreditAttribution: renat commentedSorry I wasn't clear enough from the very beginning. I meant that because of reforms pair of timezone name - timezone offset can be false as of today standards. I.E. when particular entity was created, timezone XXX was GMT+3, and now that timezone is GMT+4. So I was interested, will we see correct date in such a case. If I understood #63 right, the answer is "yes", with some additional conditions.
Comment #65
KarenS CreditAttribution: KarenS commented@renat, yes, this the reason why we need to quit using timezone offsets and switch to using timezone names everywhere, which is part of what this whole patch is about. Timezone offsets do not provide enough information to handle dates correctly, but if we use timezone names, PHP has a historical database that can tell what offset applies when.
Comment #66
KarenS CreditAttribution: KarenS commentedLatest reroll. I got rid of the code that worries about offsets vs full timezones just to simplify this. That test is needed if you want to manipulate the dates, so anyone who wants to do that can handle it themselves. I also found that my previous hope that the warning message number for the invalid date warning was consistent was incorrect. There are several different warning message numbers. But I did find that basically anything that creates a warning is something we want to consider an error -- somehow a date is created but it doesn't exactly match the input. So I switched to just treating all warnings as errors.
I now have two follow up patches to this one, one to consolidate translation of date labels into a plugable calendar system and another one I'm getting ready to post that uses these two patches as the basis for a date field in core.
But let's confirm that this one is now green. I think it should be.
Comment #67
moshe weitzman CreditAttribution: moshe weitzman commentedWell done. Just a few nits for the next reroll.
This seems vague enough that it can be removed
Cowboy debugging!
Looks to me like we can and should use UnitTestbase instead of WebTestBase
Comment #68
Wim Leers:)
Comment #69
KarenS CreditAttribution: KarenS commentedLatest re-roll. Included fixes suggested above, plus comments posted on #501428: Date and time field type in core. Hoping we can get this in soon so I can focus on #1811912: Add pluggable calendar backend to core and centralize date translation and then finally #501428: Date and time field type in core.
The comments included in #501428: Date and time field type in core include more debate about whether to use 'Drupal' in the class name. I'd like to put off that discussion to a follow up patch. The name can easily be changed later, after feature freeze, if there is agreement that it needs to be changed. I think the name makes sense, it is the Drupal version of the DateTimePlus class, that incorporates Drupal's localization system.
Comment #70
moshe weitzman CreditAttribution: moshe weitzman commentedIs there a reason we can't use UnitTestbase instead of WebTestBase? WebTestBase is much slower since it has to setup a new Drupal install. maybe pollution from the host environment?
Comment #71
KarenS CreditAttribution: KarenS commentedI changed the tests for DateTimePlus to use UnitTestBase. The test for DrupalDateTime is testing language handling and requires session management to test the language switching, so I don't think that one can use UnitTestBase.
Comment #72
KarenS CreditAttribution: KarenS commentedI meant to say it is testing user timezone preferences, not language switching, but I borrowed the method used by language switching tests to test the switch of timezone preferences.
Comment #73
moshe weitzman CreditAttribution: moshe weitzman commented@Karens - is there a new patch with UnitTestBase?
Comment #74
KarenS CreditAttribution: KarenS commented@moshe --The patch in #69 uses UnitTestBase for the DateTimePlus tests. As I noted above the other tests, for DrupalDateTime can't use that.
Comment #75
mgifford@KarenS - This is a huge patch. Really appreciate the work you've put into this.
I've applied the patch (git applied it nicely), but I don't know how to see if it is working or not.
Where is the UI changing? I had expected to add a date/time field to a content type, but couldn't see it.
Thanks.
Comment #76
arlinsandbulte CreditAttribution: arlinsandbulte commented@mgifford: The code here only adds the api to core.
Adding a date/time field to core is being handled in this issue: #501428: Date and time field type in core.
Comment #77
moshe weitzman CreditAttribution: moshe weitzman commented@mgifford - thats a follow-up patch thats in progress at #501428: Date and time field type in core. this one has ni UI changes. I reviewed the tests and am happy with this now.
Comment #78
moshe weitzman CreditAttribution: moshe weitzman commentedNo UI
Comment #79
mgiffordWell, if there's no UI, it makes it hard to test.. :)
Thanks @moshe for sending me in the right direction & marking this RTBC. Date support is pretty critical.
Comment #80
Sylvain Lecoy CreditAttribution: Sylvain Lecoy commentedBtw, this is only my opinion, but I think DateTimePlus can be merged with the drupal date time object.
Comment #81
KarenS CreditAttribution: KarenS commentedThe point of keeping them separate is that DateTimePlus can stand alone as a component that doesn't require Drupal and can be used elsewhere. DrupalDateTime adds in Drupal-specific handling for language, etc. to make it useful to Drupal.
The idea is that we're pulling out re-usable components into Drupal/Component, and Drupal-specific classes into Drupal/Core/.
Comment #82
Crell CreditAttribution: Crell commentedSeparating out the Drupal bits from the non-Drupal bits is a good practice, so this split is good. There's nearly no runtime cost, as inherited methods are basically free.
That said, there's still some bugs in the code:
Drupal coding standards specify protected is preferred over public. Why are these public?
There is no such property. It's been renamed to inputTimeAdjusted. Looks like there's a missing test if that isn't being caught.
Ibid.
Ibid.
I think because all three of these are wrong in the same way, it's passing tests because it's storing to a dynamic public property instead of a defined property above. That's why tests aren't catching it.
Looks like this property is wrong, too. I won't mention more, but there are more of these in the patch.
This could also just return (boolean)count($this->errors); Doesn't have to change, but a nice minor cleanup.
This is redundant. Just casting to a string is sufficient.
Comment #83
KarenS CreditAttribution: KarenS commentedThe changing of the variable names to camelcase was a total fail. I didn't upload the file with all those changes. The tests were OK I think because they were used consistently. I also protected the variables and a few of the methods.
Comment #84
Sylvain Lecoy CreditAttribution: Sylvain Lecoy commentedThe DrupalDateTime does not adds that much (only 2 methods and a different constructor) thus there is maybe no need for further fragmentation.
Also, I think you can also make DrupalDateTimeTest extending from UnitTest by manually setting the global conf array. Just a though, are we still using variable_get() at this point ?
Comment #85
KarenS CreditAttribution: KarenS commentedI want DateTimePlus to be a re-usable, stand-alone component, and it cannot have Drupal methods in it. For Drupal we need to add in the Drupal methods. So we need two classes.
We still have variable_get for the items in the tests, they haven't been changed to CMI yet. When they are, we have to make that change here too, but until that we have to use the variables.
Comment #86
moshe weitzman CreditAttribution: moshe weitzman commentedBack to RTBC
Comment #87
aspilicious CreditAttribution: aspilicious commentedSrry for spoiling the party. This needs a doc cleanup first.
Docs should start with a 3th person verb. And the summary shouldn't be longer than 80 chars. Underneath the summary you can write longer docs if needed.
Same goes for most of the docs.
I'm not sure we should use @see in this case. And if we use @see it should be two @see's and not one with an 'and' in between.
Like I said before this should be "CreateS". Please check the other fucntions as well.
Don't use @see in the middle of a docblock. In that case a normal "See" is more appropriate. @see elements should be placed on the bottom of the doc block. See node/1354 for more information.
Comment #88
KarenS CreditAttribution: KarenS commentedOK, updated docs.
Comment #89
aspilicious CreditAttribution: aspilicious commentedKarenS you made my day :). NICE!
Based on the previous RTBC I'm moving it back to that state.
Comment #90
catchI couldn't find much to complain about, this looks great. I agree about the class split, nice to have something else in components. it's a shame user_get_timezone() isn't anywhere near close to injectable but that's going to require the $_SESSION changes and a bunch of other stuff so we can leave it here.
A few niggles follow:
Would it be possible to figure out which of these is likely to happen most often? i.e. is there anywhere in the critical path that we're using this or are likely to, then we could put that check arbitrarily first so the others get skipped.
Why the @ to suppress errors when we're also catching the exception?
Weird indentation here.
Do we really need to create a new DrupalDataTime() object with a timestamp, then call getTimestamp() on it?
Comment #91
KarenS CreditAttribution: KarenS commentedNot really. The order of the testing is basically from things that are easiest to be sure of down to things we are less sure of, with a final fallback for everything else. We can easily tell if the input is a DateTime object or array, so we test that first and pull those possibilities out. If it isn't either of those, it might be a timestamp, and that's relatively easy to determine (is_numeric), so we check that next. If it's none of those but a format is provided, we can do this using the createFromFormat() method, so that's the next thing we can pull out. Everything else funnels into the parent class to see what it can make of things.
That's been in the code for quite a while. Basically if a date fails it is an ugly fatal failure that blows the page up even in a try/catch. We're checking for everything possible before trying that, but if it's broken at that point the error is ugly, so it's basically a last ditch effort to suppress any problems if the date can't be created. If I've succeeded in identifying every possible thing that can go wrong, it's not needed. But I'm not sure how to be sure of that.
That's the indentation my code style sniffer wants. I didn't see any Drupal code standard that said differently, so that's the way I did it.
This is an alternative to using strtotime(), which is a much less robust way to do things. The strtotime() function can not interpret dates nearly as well as the DateTime class, especially dates that are very old or far in the future. The DateTime class can do everything strtotime() can do and much more (and more reliably). Are you suggesting going back to strtotime()?
Comment #92
KarenS CreditAttribution: KarenS commentedHow about this? I changed the indentation. I'm not sure there is anything else to fix.
Comment #93
BerdirI think we usually do this:
So it's just one level deeper, and doesn't depend on where array( starts.
Comment #94
BerdirEdit: Doube post.
Edit2: And a crosspost too. Looks correct in the patch.
Comment #95
KarenS CreditAttribution: KarenS commentedMarking this back to RTBC
Comment #96
catchSorry I didn't mean going back to strotime(), the patch currently does this:
This means we have this possible code path:
REQUEST_TIME is already a timestamp, so we don't need to do that, it can be:
With the @ call, please add some docs to explain why it's necessary, ideally we'd also have a link to the PHP bug report if there is one. We have #1247666: Replace @function calls with try/catch ErrorException blocks open which might allow the error to be caught but depends how fatal it is I suppose and that patch isn't in yet.
Comment #97
KarenS CreditAttribution: KarenS commentedOK, made those changes.
Comment #98
KarenS CreditAttribution: KarenS commentedUgh, meant to say I changed the node creation item and I removed the @. I have added lots of additional ways to keep it from failing, and I can't find a way to break it right now, so maybe it's OK to leave it off now. If anyone does find a way to break it we can document that then.
Comment #99
BerdirI think that addresses catch's concerns.
Removing the @ given that there are no known cases in which this can happen sounds good to me.
Comment #100
cosmicdreams CreditAttribution: cosmicdreams commentedJust wanted to add a note that I'm aware that if this patch gets in I'll have to rework parts of #1571632: Convert regional settings to configuration system, but in my view this component approach is much preferred.
We previously setup the system.date.yml config file to allow for the persistence of multiple date format patterns. Given how DateTimePlus->format() depends on a proper $settings array, we'll just need to modify the regional CMI patch to populate the settings appropriately.
If there's somewhere in this patch where you're already doing that please point me to it. I think we're really close here.
Comment #101
KarenS CreditAttribution: KarenS commentedI think this is still RTBC, in spite of #100. If this can be committed I'll be glad to see what changes need to be made to the regional settings patch, if any. It would be much easier to get this in and then react to it in the other issue than to hold up both issues while we figure out how to patch them both simultaneously.
Comment #102
cosmicdreams CreditAttribution: cosmicdreams commentedWhoops, didn't mean to change the status. I can mark #1571632: Convert regional settings to configuration system as postponed if that helps get this one in.
Comment #103
sunThis looks great to me. Excellent work, @KarenS! :)
Would be great to move forward here.
Comment #104
Lars Toomre CreditAttribution: Lars Toomre commentedAttached is a patch that cleans up the documentation and inline code comments. An interdiff is also included.
Much of this included re-wrapping text to better use 80 character limit.
Where I was unsure of what needed or expected, I used the text string '???'.
Comment #105
tim.plunkettWhy did you change these lines? Please stop trying to enforce your personal coding standards on every patch in the queue.
This is STILL not correct according to the coding standards. But, that's coding standards not docs.
That doesn't really help much. But these are the only parts that need to get fixed before this goes in, the rest is a follow-up.
Comment #106
Lars Toomre CreditAttribution: Lars Toomre commentedAccording to the work on-going in #1446366: [meta] Multiple web test classes mislabeled as unit tests. simpletest ([Web|Unit|DrupalUnit]TestBase), DateTimePlusTest.php should be renamed to DateTimePlusUnitTest.php.
Comment #107
sun@Lars Toomre: Can you remove all new lines that contain "???" from #104, please?
Otherwise, let's go ahead and commit #97 and apply/commit the interdiff of #104 (or any newer/corrected) afterwards.
Back to RTBC for that.
Comment #108
webchickAWESOME work!!
Looks like catch's concerns have been addressed. We are above thresholds by a couple of major bugs, but I think it's strategically important to get this in, so we can continue to build off of it until feature freeze.
Committed and pushed to 8.x. Thanks!
Comment #109
arlinsandbulte CreditAttribution: arlinsandbulte commentedKarens++
Karens++
Karens++
Karens++
Karens++
Karens++
Karens++
Karens++
Comment #110
catchWe need a change notice for this. Also yay!
Comment #111
KarenS CreditAttribution: KarenS commentedI'll work on a change notice later today. Thanks everyone!!!
Comment #112
KarenS CreditAttribution: KarenS commentedChange notice added: http://drupal.org/node/1834108.
Comment #113
Tor Arne Thune CreditAttribution: Tor Arne Thune commentedComment #114
fagoI've created a related follow-up, please see #1844956: Optimize date formatting performance.
Comment #116
TonyScott CreditAttribution: TonyScott commentedI don't know if this has been dealt with (I haven;t had a chance to read through all the comments) but the example given in an early comment, that the validation isn't or wasn't catching an invalid date such as 2/21/2014 misses the point that this is a VALID European date.
I was really hoping the codesprint in Kiev this weekend would solve the problems preventing me from creating a select by date range interface for my users, but it doesn't look like they even got to it. So I'm putting in a plea here: PLEASE, yes, a very robust date function is NECESSARY in core for D8!