Can we get a "sort by" option for Date fields in Views' Sort Criteria?
For example, if I were using a CCK Date field to represent birthdates, I'd want to create a view that filters on the current month and sorts on the day, without regard for the year of birth. That would allow me to present a "Birthdays this Month" block sorted in day order. Currently, I can only sort on the full date field, so people born in earlier years would appear first, regardless of on what day of the month their birthday falls (i.e. someone born on 9/2/1950 would sort above someone born 9/1/1970).
I'd be happy to contribute code for this, if you can point me in the right direction... Specifically, how to hook into the existing date/cck definitions to add sort options and handlers. I've read through the relevant documentation on CCK and Views, but can't find where those hooks would be implemented in Date.
Comment | File | Size | Author |
---|---|---|---|
#13 | datesort.zip | 3.24 KB | skybow |
Comments
Comment #1
dtabach CreditAttribution: dtabach commented+1, I also would love this feature.
A workaround would be to use computed field to extract month and day from a cck date field, but I don't know how to do this. Any help would be great.
Comment #2
KarenS CreditAttribution: KarenS commentedNo new features in D5, moving feature requests to D6.
Comment #3
dtabach CreditAttribution: dtabach commentedI found out how to achieve the workaround I suggested in #1. Hope this is useful for someone else.
How to create a 'Next Birthdays' View, showing a list of users sorted by day and month of birth, disregarding the year:
- Add a cck computed field to your Profile called next_birthday, which will caculate the date of user's next birthday based on his date of birth (field_date_of_birth). If the day and month of birth is equal or greater than today, next birthday will be the day and month of birth in the current year. Otherwise, next birthday will be the day and month of birth in the next year.
- Put the following code in the 'Computed Code':
- Check 'Store using the database settings below'; Date type: 'varchar'; Data lenght: 128 (I really don't know exactly what to put here, but 128 worked!); Check 'Sortable'.
- You will have to resave all already existing Profile Nodes for the new field to be calculated. To do this, put the code below in the body of a new node with PHP code filter:
- You can then sort your View by Computed:Next Birthday. Filter the View by 'date of birth:year is greater than 1900', to exclude the Profiles in which users did not fill in the field.
Suggestions on how to improve the snippet above would be appreciated.
Comment #4
avior CreditAttribution: avior commentedIs that the only way doing this in 6.x ?
Comment #5
vasikesubscribe, for Today in History (On this day ... ) functionality.
Comment #6
wylbur CreditAttribution: wylbur commentedThis snippet works, until time passes, and the Next Birthday date stored in the database passes. To keep this working, you need to recaculate the calculated values in the profiles.
I tried to remove the storage of the computed field, but then it is not available for my views.
The storage feature would work if you could execute the code in the profile update page as part of the cron tasks. Is this possible?
So my workaround is to run my Next Birthday Update code via the page I created as if it is a cron job - which it is now! I run it once a day to update the upcoming birthday for all users. Seems like a waste of resources, but it works for now.
Comment #7
ogi CreditAttribution: ogi commentedsubscribe
Comment #8
dtabach CreditAttribution: dtabach commentedYes, wylbur, you are right. The profiles must be saved regularly to keep the next birthday info updated.
Could you explain how you run your Next Birthday Update code as cron job?
Comment #9
magnestyuk CreditAttribution: magnestyuk commentedsubscribing
Comment #10
ugly_baby CreditAttribution: ugly_baby commentedsubscribing
Comment #11
finke77 CreditAttribution: finke77 commentedHello all together,
here is the cron job (as a seperate module) executed once a day (see also: http://drupal.org/node/435992):
I haven't tested it up to now, but I will do it, because I have exact the same situation/problem. Maybe next week if I have the time ...
I hope this will help!
Best regards,
Chris
Comment #12
skybow CreditAttribution: skybow commentedsubscribing
Comment #13
skybow CreditAttribution: skybow commentedHi everybody,
since there were a number of people asking for this, including myself and since I wanted to get things done and since the actual code is really not that complicated, I sat down and wrote a small module that (hopefully) does what has been requested here. So I proudly present a prerelease version of a thing that I call "datesort" module for now.
It is an enhanced duplicate of the
views_handler_sort_date
. Besides fixing a bug when not used with datestamp (a.k.a. unix date stamp) field, it adds a birthday mode and as a further addition a round robin offset.The offset can be used to shift the today value back in time. So with an offset of 7 you get the birthdays of last week shown first in the sorting.
I have not (yet) checked in this code to make it available as project because I think it should be either part of the date module or cck or views. I'd be willing to check it in, maybe with a slightly different name – i.e. "birthdaysort" if nobody is willing to integrate this.
The code could directly be used to replace
views_handler_sort_date
since it originates from this class.The only other thing that needs work is to add code that will use this handler instead of
content_handler_sort
in CCK date fieldsComment #14
arlinsandbulte CreditAttribution: arlinsandbulte commentedI marked the following issues as duplicates of this one:
#468456: Views filter separately for each component of the date field (YYYY) (MM) (DD)
#410856: Date argument to get same day and month date but different year
#448628: Exposed Date Views filter could ignore year
#219794: Allow dates without years.
By anniversary-type events, I mean events that happened in the past, but are celebrated or recognized on a yearly (or monthly or weekly or daily or hourly?) basis.
Examples include: Birthdays, historical events, wedding anniversaries, other anniversaries, etc.
I have not fully gone through all the comments & code above, but one thing that might be possible is to use a cck computed field(s) for this purpose (http://drupal.org/project/computed_field).
A computed field could extract month & day information from the date and store those values. Then you can use views to easily filter/sort on the computed fields instead of the full date.
Integration into the calendar views/grids might be another issue... dabtek's method sort of gets around that, but there are drawbacks as noted above.
Comment #15
skybow CreditAttribution: skybow commentedSince I'm not a native english speaker, I wasn't sure how to call the thing. I like your term "aniversary-type" and it is exactly what I proposed in the module attached in #13. Replace birthday with aniversary-type and I think this is what you want.
I haven't posted this as a separate module since I think it should be somehow integrated into the date module.
Also note that I have not checked the results with Calendar View (yet).
Comment #16
dtabach CreditAttribution: dtabach commentedHello skybow, does your datesort module works with Drupal 5.x (the original version this issue was created)?
Comment #17
skybow CreditAttribution: skybow commentedI started with D6 and have never used D5, so I can't tell.
If the Views API for D5 is similar to the one for D6, then it should be possible to backport the filter though.
Comment #18
lukio CreditAttribution: lukio commentedHi, excelent module (datesort). Was exactly what i need!!
why don't you create a project at drupal.org with these module?
cheers!
--
Luciano Rossi (lukio)
Comment #19
skybow CreditAttribution: skybow commentedHi lukio,
I have not posted it as module since I think that this belongs into either CCK, Views or probably best into the Date module in the first place. Especially since the net amount of code that does the logic is rather small compared to the overhead of replacing the Views' sort handler. I'm not sure how much overhead there is to having an awful lot of modules for rather tiny pieces of functionality, and maybe it is not that much in a production environment where you don't have to change the module settings a lot. But I experienced rather long waiting time when I need to enable/disable a module, the more modules I have.
But true, I'm surprised that none of the responsible persons made even a note that this showed up on their radar.
I'll give it another one or two weeks until I will make this a drupal project.
Cheers
Comment #20
bocky CreditAttribution: bocky commentedGreat module (datesort). But what i need is to show "birthdays, anniversaries" only for today's date (for example all content for 25.11). Is it possible to achieve this with this module?
Comment #21
skybow CreditAttribution: skybow commentedIt's been a while, since I last looked at the code. However, from reading my own comments, I think you can't because I only defined a sort handler. What you need is a filter that is able to ignore the year portion of a date.
I will think about adding this to my code, but right now I'm rather busy, so please don't expect this to happen very soon.
Comment #22
bocky CreditAttribution: bocky commentedThank you for quick response. Yes it is a filter what i need.
Comment #23
daph2001 CreditAttribution: daph2001 commented@arlinsandbulte, thanks, that's a really good solution.
Hope to see inside the Views module in the future.
Comment #24
R.Hendel CreditAttribution: R.Hendel commentedsubscribing
Comment #25
cardentey CreditAttribution: cardentey commentedsubscribing
Comment #26
TravisCarden CreditAttribution: TravisCarden commented+subscribing
Comment #27
bocky CreditAttribution: bocky commentedany news ?:)
Comment #28
OliverColeman CreditAttribution: OliverColeman commentedI could definitely use the ability to filter by month only! This is vaguely similar to the issue I just posted about the Optional option not working for exposed Date filters: #717682: Views filter "optional" option not working?
Comment #29
R.Hendel CreditAttribution: R.Hendel commented@OliverColeman:
could you please export that view here?
I would like to know if this matches my request or if I have to describe it in a more detailled way.
Thanks in advance.
Comment #30
OliverColeman CreditAttribution: OliverColeman commented@R.Hendel
I no longer have the view to export as I'd actually like it to work as I've implemented it for now using the module in #13. Basically what I've got is some profile nodes with a date of birth (year/month/day), and I want a view with a Date filter that filters by the month only and ignores the year, thus listing all birthdays that occur in that month.
I think what's different in my case as opposed to what most people here want is that I want to expose the filter and have it default to the current month (with no year field displayed (either that or just have the year field default to an "any" option and then I can hide it with CSS)).
However, for both what I want and what I think most people here want, this would only work if it was possible to select relative values separately for year, month and day in the filter settings form (for example leaving year and month blank and selecting "now" for the day)
The way I've implemented it at the moment, with the datesort module in #13, is that it displays the first 50 profiles who's birthdays occur after 7 days ago (the offset setting is set to -7). Let me know if you want me to export that. This view is for administrative purposes only so it doesn't matter that it displays a few extra profiles with birthdays in the next month or two (and in fact it displays a pager so you could see all profiles with birthdays occurring throughout the year).
Comment #31
R.Hendel CreditAttribution: R.Hendel commentedHi Oliver,
thanks for your detailled answer.
In fact we have another and more complicated request: We want to have one single calendar (using calendar module) which should display events AND birthdays. This is very complicated as there is just one single argument field which matches the records. Of course this calendar should display birthdays annually and not only the users, which are born today :-)
@all:
We are going to develop a special module for this. I will leave a comment here, as soon as it is submittet - hopefully in two weeks. If I will forget this, please remember me :-)
Best regards,
Ralf
Comment #32
OFF CreditAttribution: OFF commentedAny updates?
Comment #33
RedTop CreditAttribution: RedTop commentedI would love this feature!Up til now I just misused the 'node: Post date' field. View's style allows you to group by field and the Node: Post date field can be configured to output a custom date format (for example year only). This is a wonderful way of creating archives of nodes, sorted by year.Today I realized that this is a rather dirty way of doing things and that I should probably use the Date module for 'real' dates and Node: Post date for its intended use. Unfortunately Date doesn't seem to offer the option to output a custom date-format in Views...Sorry, I found the solution about 10 minutes after posting this. I had to add a new format (year only) to the datetime field I created for the content type and set that as default display.
Comment #34
arlinsandbulte CreditAttribution: arlinsandbulte commentedtweaking title to make it easier to search for
(I just had a hell of a time finding it...)
Comment #35
Stephen Scholtz CreditAttribution: Stephen Scholtz commented(For anyone who stumbles across this while searching...)
re: comment #14....
A computed field might be useful for sort, but not for filter. The computer field would end up being an integer, and the Views numeric filter doesn't support dynamic values as criteria.
ex. I might have a computed field made up of the month concatenated with the day, like "520" (May 20th), but the numeric filter only support hard coded values, so I couldn't pass in, say
date("nd")
ordate("nd") + 5
or whatever.You can, however, use computed field + an argument: provide a default value + PHP code and you could
return date("n")
but that's only good if you want to get a list of birthdays or events that would have a given month, or a particular day (usereturn date("nd")
for a day value).(And for anybody who knows more about Date/Views internal workings than I do, the interface for the Date filter is in date/includes/date_api_filter_handler.inc ...I don't know enough about creating custom filters to edit this class and add in a "birthday mode" similar to the datesort mini module)
Comment #36
zoo CreditAttribution: zoo commentedAny solutions/news about filtering only by month or day or year? Thanks.
zoo
Comment #37
boazr CreditAttribution: boazr commentedWhat I did in order to sort by birthdates is to hook into views api and change the sorting (assuming my module is mymoudle, the view is employees, the display im after is block_2 and the birthday field is called field_bd):
function mymodule_views_query_alter(&$view, &$query){
if ($view->name == 'employees' && $view->current_display == 'block_2') {
$query->orderby[0]= "((DAYOFYEAR(node_data_field_bd.field_bd_value) - DAYOFYEAR(NOW()) + 365 ) % 365) ASC";
}
}
This gives a nice sort by the nearest birthdays, and is simple to implement :)
Comment #38
flokosiol CreditAttribution: flokosiol commentedThanks a lot, boazr. This is a great, clean solution.
Comment #39
boazr CreditAttribution: boazr commentedthanks groovekanister.
This worked nice, until some days got mis-sorted by a difference of 0-1 day, leading to the discovery that DAYOFYEAR is different every 4 years (FEB has 29 days then). So you have to change the sort critera as follows (convert the dates to "this year" to sort correctly):
$query->orderby[0]= "(
( DAYOFYEAR( DATE_ADD( node_data_field_bd.field_bd_value, INTERVAL (YEAR (NOW() ) - YEAR(node_data_field_bd.field_bd_value)) YEAR ) )
- DAYOFYEAR(NOW()) + 365 ) % 365) ASC";
A little more cumbersome on your db cpu, but works perfectly.
Comment #40
muschpusch CreditAttribution: muschpusch commentedOke... one more for getting only today's birthdays:
Comment #41
OFF CreditAttribution: OFF commentedI solved this problem by using the module "views php filter" and this code:
Comment #42
mtcs CreditAttribution: mtcs commentedThanks for this solution!
It has a small problem, however: "views php filter" will not add any WHERE clause to the SQL query if the $nids array is empty. This means that all nodes will be selected when nobody has a birthday. A dirty hack could be to add this line before the while statement: $nids = array(-1);
Comment #43
OFF CreditAttribution: OFF commentedthanks
Comment #44
mtcs CreditAttribution: mtcs commentedI've also noticed that this solution didn't handle node revisions.
You can filter out previous revisions by joining the "{node} n" table and checking for n.vid = c.vid (c is the content_type_xxx table).
Comment #45
Sinovchi CreditAttribution: Sinovchi commentedI'm using date and cck field for statistics. I have a half year, 9 months and annual statistics for the last 10 years. All these statistics are saved in nodes and cck date field - in "from date" and "to date" fields.
Now I want to select annual statistics and half year statistics in different views. Do I need filtering only by month option or is there any other possibility to do this job?
Thank you!
Comment #46
locomo CreditAttribution: locomo commentedsubscribe
Comment #47
richardtmorgan CreditAttribution: richardtmorgan commentedSkybow's 'datesort' module posted at #13 was just what I needed - thanks so much.
I found that the 'round robin' setting of '0' did not do the job though - it only worked if there was a non zero number.
On line 71 of datesort_handler_sort.inc the if condition for whether to apply a 'round robin' is expressed like this:
if (!empty($offset)) {
The problem is that empty() returns true for a value of '0' - so to be able to use the round robin function as described I changed this line to:
if (!empty($offset) || $offset === '0') {
Now if I leave the 'round robin' value empty I get birthdays sorted from January 1 and if I set 'round robin' to '0' I get birthdays sorted from today.
Comment #48
tfo CreditAttribution: tfo commented+1
Comment #49
handinherpocket CreditAttribution: handinherpocket commentedSkybow's module in #13 is perfect for Today in History lists. Thanks!
Comment #50
eL CreditAttribution: eL commentedused #13 and it works, but it messed up all my other Views sorted normaly upon whole date :(
Comment #51
vinoth.3v CreditAttribution: vinoth.3v commented+1
Comment #52
sbandyopadhyay CreditAttribution: sbandyopadhyay commentedSince it's been over three years, I think it's safe to say this issue won't get fixed in Date.
The module in #13 has been widely used, and although I had a few small problems with it (including that it clobbered the default functionality of other views that I didn't want this granularity on), it was a great inspiration for creating a new module, which I've just released: Views Date.
It has a few benefits over skybow's module in #13 (it doesn't hack the default sort criteria, but rather creates a new one; it allows you to pick more than just the month/day combination in "birthday mode"; the Date module is not a requirement) but it also has a few drawbacks (the round-robin mode isn't really working, nor does it support the CCK "Date" field type [although it does support Datetime and Datestamp]).
Comment #53
eL CreditAttribution: eL commentedsbandyopadhyay: thanks a lot!
Comment #54
rsgracey CreditAttribution: rsgracey commentedAnd for D7....?
Comment #55
OFF CreditAttribution: OFF commentedFor drupal 7 you need only views module for do that.
1. Add date field "field_birthday"(for example) in the user entity.
2. Add views of type "user"
3. Add contextual filter "user id" with checkbox "Allow multiple values"
4. Place this code to the "PHP contextual filter code":
$results = db_query("SELECT entity_id FROM field_data_field_birthday WHERE DATE_FORMAT(field_birthday_value,'%m-%d') = DATE_FORMAT(NOW(),'%m-%d') AND entity_type = 'user'");
$ids = array();
foreach ($results as $result) {
$ids[] = $result->entity_id;
}
return implode(',',$ids);
Demonstration: http://blondie.ru/birthdays
Comment #56
lunk rat CreditAttribution: lunk rat commentedCheck this out: try changing the Aggregation settings on your sort criteria to "Minimum" or "Maximum". For me this allowed sorting at the granularity level specified in the field.
Idea came from http://drupal.org/node/1431780
I wanted to aggregate and group together a date field (coming from a relationship, plus using Views date format SQL) at the month level and sort by month. Every time I added a sort field, my aggregation would stop grouping.
I set aggregation settings to Minimum on my sort criteria and it sorted as desired without breaking aggregation.
Comment #57
jos_s CreditAttribution: jos_s commented#55 was just what I needed! Thanks for sharing. I have been spending many hours on finding a solution for this.
Comment #58
Fernly CreditAttribution: Fernly commented#55 is working solution for D7. However, a filter on day or month only should be default behaviour of Views.
Note that for multiple values to work, the validation criteria of the contextual filter has to be enabled and at least set to 'Basis validation'.
Comment #59
thentha18 CreditAttribution: thentha18 commented#55 Worked for me on D7
Comment #60
preksha CreditAttribution: preksha commentedFor Drupal7,
@OFF, I did not understand "3. Add contextual filter "user id" with checkbox "Allow multiple values"" , where can I find the checkbox to "allow multiple values"?
Everything is working fine but it displays only one value not multiple. Am I missing the configuration of this checkbox "3. Add contextual filter "user id" with checkbox "Allow multiple values"" that's why it's not working?
Comment #61
preksha CreditAttribution: preksha commented@OFF, Now I got from where "Allow multiple values" comes and I have enabled it. But still it's not working for multiple users.
Could you please give me any hint? Any solution is welcome. :)
Comment #62
preksha CreditAttribution: preksha commentedSorry, I found the solution. I have enabled validation criteria to user->numeric uids. But as per #58, I have set validation criteria to Basic Validation and it works fine now. :)
So #55 works cool.
Comment #63
tinohuda CreditAttribution: tinohuda commented#55 is work for me. Cool.
Comment #64
colan#468456: Views filter separately for each component of the date field (YYYY) (MM) (DD) should do the trick for this one.
Comment #65
martin.l CreditAttribution: martin.l as a volunteer commentedsubscribing.
Comment #66
omkarms CreditAttribution: omkarms commented@OFF, can you please help me, where to put this code,
$results = db_query("SELECT entity_id FROM field_data_field_birthday WHERE DATE_FORMAT(field_birthday_value,'%m-%d') = DATE_FORMAT(NOW(),'%m-%d') AND entity_type = 'user'");
$ids = array();
foreach ($results as $result) {
$ids[] = $result->entity_id;
}
return implode(',',$ids);
Actually I have any Entityform, where i want a View for next week birthdays with Date and Month only excluding Year, to be displayed in view.
what do i need to do?
Thanks
Comment #67
omkarms CreditAttribution: omkarms as a volunteer and commented@OFF, I got the PHP code option, i also pasted that code in that, but is not working,
I took
1. Name
2. Date of Birth into Fields
I followed the procedure of CONTEXTUAL FILTERS as you mentioned, what do i need to take in FILTER CRITERIA ?
Thanks