Hacker News new | past | comments | ask | show | jobs | submit login
Pickadate.js (github.com/amsul)
278 points by electic on Nov 20, 2012 | hide | past | favorite | 125 comments



A few random comments...

This value is not what it says:

    SECONDS_IN_DAY = 86400000,
That's the number of milliseconds in a day. Instead of a magic precalculated number, why not create all the relevant constants so the values become perfectly clear:

    HOURS_IN_DAY = 24,
    MINUTES_IN_DAY = HOURS_IN_DAY * 60,
    SECONDS_IN_DAY = MINUTES_IN_DAY * 60,
    MILLISECONDS_IN_DAY = SECONDS_IN_DAY * 1000,
Personally, I find these kinds of string constants get in the way:

    STRING_DIV = 'div',
    STRING_TR = 'tr',
The string 'div' is never going to change to something else, is it? It would be better to just use the string directly where you need it.

This is an amazing and scary piece of code:

    /**
     * Get the count of the number of
     * days in a month, given the
     * month and year
     */
    getCountDays = function( year, month ) {
    
        var
            // Set flip based on if month is
            // before or after July
            flip = ( month > 6 ) ? true : false
    
        // If it's February
        if ( month === 1 ) {
    
            // If it's not a leap year
            // then 28 otherwise 29
            return ( year % 4 ) ? 28 : 29
        }
    
        // If it's an odd month ID
        if ( month % 2 ) {

            // If it's after July then 31
            // otherwise 30
            return ( flip ) ? 31 : 30
        }
    
        // If it's an even month ID
        // and it's after July then 30
        // otherwise 31
        return ( flip ) ? 30 : 31
    }, //getCountDays
It also calculates leap years incorrectly - try getCountDays(1900,1). February 1900 had 28 days, not 29.

Why not let JavaScript do the work for you?

    getCountDays = function( year, month ) {
        var msInMonth = new Date(year,month+1) - new Date(year,month);
        return Math.floor( msInMonth / MILLISECONDS_IN_DAY );
    },
This will handle all leap years correctly.

You can probably do something similar in your createDate function to avoid the manual tests.

Also the name getCountDays is not very informative. Maybe getDaysInMonth?

The settings options use names_with_underscores, but that's not very idiomatic in JavaScript (except for capitalized constants). camelCaseNames would be more comfortable.


Just a followup on my "amazing and scary" comment. The "amazing" part is a genuine compliment: you found a pattern in the number of days in each month that I never noticed (the 'flip' trick). Being able to see these kinds of patterns and take advantage of them is an invaluable skill in programming.

The problem here, of course, is that it makes the code a lot harder to understand. To understand and verify the function, I'd start by writing out a table of the days in each month while reciting the "30 days hath September" rhyme. :-) Then I'd have to go through all the the flip and non-flip cases in the code and compare against my table.

Let's imagine that JavaScript didn't have convenient date calculations so we couldn't use the updated function I posted above. If that were the case, what would be a simpler way to code the function? Just use the table of months directly. After all, there are only 12 months to deal with, so it's very simple:

    getCountDays: function( year, month ) {
        var monthDays = [
            31,  0, 31, 30, 31, 30,
            31, 31, 30, 31, 30, 31
        ];
        return monthDays[month] || getFebDays( year );
    },
where getFebDays() handles all the special cases for leap years ( /4, /100, /400, etc.)

Now, with the exception of February, it's trivial to see at a glance if the function is correct.


Looks like you were trying to send pull requests?


Ha! I was thinking about my version of getCountDays() and realized there was probably a bug in it. Did anyone else see it?

  getCountDays( 2012, 2 )  // Daylight time began March 11
  30  // oops
new Date(year,month,...) uses local time, so the day will be an hour longer or shorter when the time changes.

A quick and dirty fix would be to use Math.round instead of Math.floor:

    getCountDays = function( year, month ) {
        var msInMonth = new Date(year,month+1) - new Date(year,month);
        return Math.round( msInMonth / MILLISECONDS_IN_DAY );
    },
And maybe better to use UTC? (I'd stick with Math.round at the same time.)

    getCountDays = function( year, month ) {
        var msInMonth = Date.UTC(year,month+1) - Date.UTC(year,month);
        return Math.round( msInMonth / MILLISECONDS_IN_DAY );
    },


From the demos it appears that this doesn't have keyboard support. That seems like a major drawback from an accessibility standpoint.

It does look nice and easy otherwise, though.


Yeah, I agree. There doesn't seem to be an easy way to choose a year. Intuition tells me "this is a text box, I should be able to just edit that text" but it won't let me.


I thought that when I use it as a textbox it would automatically auto complete and hint a month, or dynamically show calendar selecting date while I'm typing, it did neither of those things.

Also I haven't looked at the API that hard, but from the examples it looks like it only supports american way of setting the date i.e. DD/Month/YYYY

Update: another big omission, I can select year only by scrolling through it month by month. i.e. try selecting February 12, 2016


Isn't the American way Month/Date/Year?


Keyboard support for entering a date manually would be great. The GUI is great. Would like to see what the author could come up with for a pick a time.


Fork, fix and contribute.


Done:

http://news.ycombinator.com/item?id=4812223

It is even done without html5 input/type=date so probably is compatible with IE4


A javascript date picker? Is HN being very expertly trolled?


No. DatePickers, along with Forms, are the bane of my existence. More choices that are brought to light, the better.


Agreed! I had no idea how many bad ones there were until I needed one for a project.


And yet you keep us in suspense...


There you go - this will make your life easier then:

http://dojotoolkit.org/reference-guide/1.8/dijit/form.html#d...


Please, never use the Dojo Toolkit. I was forced to use it on a project and working with it was reinventing the wheel while pulling out hair. It was overly complicated for something that needed to be straightforward and simple.


Amen to that. The doc for it sucks too (not that there's enough there, but most doc for it found by google et al is obsolete/deprecated. And last but not least... the plugin ecosystem for dojo sucks even worse, and whatever widgets/dijits actually exist for it, usually look like @ss. The only one who seems to be committed to dojo is...IBM.


ESRI the top worldwide provider of GIS software is also sold on Dojo and Dijits. I agree that their digits are uglier than Android Cupcake. I have had to use Dojo on several projects now and I also agree on how abysmal their docs are. They provide tiny little code snippets but aren't even clear of the context. "Ok, fine... where do I PUT this snip... isn't this a TUTORIAL???!!??" I've been much happier with the look and feel of ExtJS but its documentation is even worse.


Out of curiosity - what did you had to reinvent? The whole point is so that you could use existing components provided to you.


Too bulky in my opinion. I don't need 90 percent of the things in that sdk.


I should add, I also feel like these big frameworks have all the components and dont do a good job of each component. I rather use something that is by itself but the author is passionate about the widget and it is the best it can be.


It should not be a matter of "feeling", but testing things out. Usually frameworks like Jquery UI, YUI, dojo toolkit do a very good job, jquery doesn't provide any widget infrastructure, but still it does a good job afaik.


so dont require them, you only use/build what you want. Its AMD and everything is nicely separated


I don't really like Dojo, but their system is so modular, you don't have to include 90% of stuff. Kinda like jQuery-ui, you can choose not to include all the other cruft.

Now with Dojo AMD (1.7+) it's even better and cleaner. You only require what you need and then build.


Amen to that


Preach!


One issue: when you change the input type from "date" to "text", you lose the common backend format that date input fields are supposed to have. With a normal date input element, input.value returns a date in the format "yyyy-mm-dd" regardless of the display format (in Chrome, at least), and the submitted POST/GET variables reflect the same format. With your date picker, I get values like "31+October%2C+2012". Is there any way to modify your library to mimic the former behavior? Otherwise, you might want to note in your docs that this date picker might require tweaking your server side form processing code.

Here's an article describing the behavior in Chrome: http://updates.html5rocks.com/2012/08/Quick-FAQs-on-input-ty.... That behavior's in line with the current spec: http://dev.w3.org/html5/spec/forms.html#input-author-notes.

EDIT: I just realized that the OP might not be the author, so I'll just add an issue on GitHub.


https://github.com/amsul/pickadate.js/blob/gh-pages/pickadat... the code is a giant var statement. I don't know why, but somehow that bothers me.


The lack of semicolons and the use of jshint bothers me.


The fact that the code is very neat and is well documented bothers me.

Also the fact that javascript is a lot more readable when you put a blank line between every two lines bothers me (a lot!).

And that it works perfectly and looks great, man that bothers me.


    // If datePassed is true
    else if ( datePassed === true ) {
Yes, very well documented. >.>


Indeed. In fact, I'd posture that the comments, after the first, are wrong; the lines' intents are to _set_!

    // Set the element as readonly
    element.readOnly = true

    // Get the date today
    DATE_TODAY = P.getDateToday()

    // Get the date to select
    DATE_SELECTED = P.getDateSelected()

    // Get the month to focus
    MONTH_FOCUSED = P.getMonthFocused()

    // Get the date ranges
    DATE_MIN = P.getDateRange( SETTINGS.date_min )
    DATE_MAX = P.getDateRange( SETTINGS.date_max, 1 )


  // Return the calendarObject
  return calendarObject
It's like this all the way through the code!


It doesn't lack semicolons, it's only using them where necessary.


looks like a single var pattern inside an immediately invoked function expression to me. works well and great for readability


Thank you for not calling it a "self-executing anonymous function".


I'm a proponent of simply calling them 'immediate functions'.


Yea, I'm not a fan of this pattern, it's a pain to step through with a debugger.


Sometimes I feel like the JS community is more concerned with "style" than practicality. I always do one variable per var, so much more readable and much easier to debug.


>6k and a jQuery dependency? Dates aren't as hard as they used to be. I'm working on a pure-JS datepicker for modern browsers that will clock in at under 5k minified, with no dependencies. Take a look at my work so far here: https://github.com/potch/fortnight.js

(Edited to correct that the likely final minified size will be closer to 5k. Hoping to add accessibility features and localizability.)


Freezes up Chrome 23, Firefox 16.0.2 (shows "stop this script?" box) and Safari 6.0. Opera does not freeze, but the UI is very slow, suggesting something is still wrong.


I believe I made a huge mistake in my calendar rendering code. Hoping it's fixed now. Sorry for freezing!


It's still happening. Now (unlike before) it does show the widgets, but Chrome goes up to 100% CPU and nothing happens when I click the widgets.


I can't reproduce- what version of chrome are you using? I'm re-evaluating all my loops to increase general safety.


Your date arithmetic jumps through some weird hoops to accomplish something really simple. To increment a date by one day, for example, can be done like so:

      d = new Date(base);
      d.setDate(d.getDate() + 1);
Changing rel() to do this fixes the loop problem, but something else is surely wrong, because the result page now looks like this: http://i.imgur.com/ZUAJg.png


Chrome 23 on Mac. Still happening with FF, even after upgrading to 17.0. FF's "Unresponsive script" alert box mentions line 103.

It's not just loops that can trigger this stuff. It's also callbacks that trigger the same callbacks.


It's the "while (!done)" loop. next(2012-09-24) returns the same date. Not sure why yet.


I have always wondered why javascript date pickers were always over complicated for the job.

https://github.com/listenrightmeow/daterange

Under 5k/100 lines uncompressed. You can easily modify above to work in a prototype fashion without a library. Unfortunately I was lazy when I wrote it and used ender/jquery for selector support.


If you are going to offer something you claim to be better, it should be better. I did a "git clone" and opened the example:

* The example looks unappealing. Not styled, not bound to a text field.

* It's not clear to my why clicking twice in a row produces a range — should this not be accomplished through mouse dragging or similar?

* If I select an end date that precedes the start date, it shows an alert box, which apparently is hardwired into the library. Not only does this make it impossible to translate the widget into multiple languages, but it's really not the task of the library to handle the error like this (an "onInvalidRange" or similar should be provided for the app to plug in).

* Month name is hardwired, no translation possible.

* No week numbers.

* No highlighting of today, holidays, or indeed of the selected range.

* No way to plug in custom dates that should be highlighted (for example, "booked" dates).

In other words, this is incomplete. I can't speak for most people, but it's useless to me. Sure, I could take your code and extend it to fit my app, but I could just as easily write it from scratch -- which defeats the point of reusability.

Sorry if this comes across a bit harsh, but you did open yourself to criticism:

> I have always wondered why javascript date pickers were always over complicated for the job.

Frankly, I suspect you have underestimated the job. :-)


i enjoyed this post.


It makes my Chrome and IE9 freeze because of an infinite loop at #228 in the demo.


Thank you for the bug report!


Looks like Chrome's native date pickers are competing with fortnight. When I click on one of the input fields, while holding the click in, I get a fortnight picker. As soon as I let go, I get a native picker.



Very nice.

1) I think you should put a little tiny triangle / down arrow on the right side of the text-box to give it the official "selection" ui signal.

2) I think you should NOT grey out dates that have already passed and are not selectable but instead keep them the same black color as the others, just <strikethrough> them. They're really hard to see when grayed out that much and it confused me a little bit when I first saw the month.


Nice. It needs a way to "click off" the picker to close it, without choosing a new date. E.g. the date is pre-selected, I open it, and then I want to close it again without changing the date. I intuitively expected that if I click the original field it will toggle off again, or I clicked elsewhere on the page it would close, like a lightbox overlay.

(tested on iPhone iOS 5.1)


Would love a matching time picker. Anybody know of a good one?


Here's one: https://github.com/perifer/timePicker

Demo: http://labs.perifer.se/timedatepicker/

(I'm not the author.)

Edit: Added link to demo since that's the first thing I usually look for.



Deperately needs localisation support. In the UK weeks start on Monday, not Sunday as they do in the US. This is a big deal.


Is it really critical? If you take the datepicker of the TFL official website (http://www.tfl.gov.uk/) they start the week on sunday too. But I agree it can be a pain when you assume the first day is monday.


Yeah, I've booked travel on the wrong dates before because I've selected the dates visually. Really annoying. As you've spotted it's an endemic problem in the UK, and it needs fixing. Even Apple get it right, and they have a strong bias to USA-ify (at least more than, say, Microsoft).


And this is why the author will slowly realize why the other datepickers aren't so "lightweight" - because they solve a hard problem.


I like this, but as others have mentioned keyboard input/editing of dates would be nice.

While we're on the subject of date pickers, is there a favorite among HN users? What have you all used for your web apps?


Does December work? :3


That was my first question too! So I tested it and it comes with December. Actually, it has all of the 12 months - no sacrifices there. Amazing stuff.


Phew, thanks for this. Now I can sleep at night again.


What I would really love is for someone to provide both a date and time picker. For some reason everybody is concerned only about the date.


I found the copy on the demo page to be very clever in anchoring different emotional cues to specific days of the year.


There is some strange bug in which I cant navigate more than one month before or after. It happens after I fill the initial date box. And then as I play around with the other dropdowns, I suddenly won't be able to move more than one month back or forward in any of the dropdown pickers.


Could really use a paired time picker. Good script though.



I'm still completely baffled that Dojo doesn't seem to get as much love as it should.


It has a reputation for bad docs etc... But they corrected a lot of that recently


This is a beautiful interface, but it doesn't provide any practical way to select dates in the distant past. "What is your birthdate" is one of many example questions that couldn't be answered without tens of dozens of clicks.

If it supported keyboard input, that problem would be solved.


HTML5 has type="date" for input fields. It'd be kinda cool if this could automatically use those in situations where the browser doesn't support the picker natively. Unless I totally misunderstand the point ;-)


That would be up to the consumer. If you look at his demo code he attaches it to `input[type=date]` already:

https://github.com/amsul/pickadate.js/blob/gh-pages/index.ht...


Support for input type="date" can be tested by creating an element like that and checking the type attribute. But how can you tell if the browser has support for the native picker? You can't. That is why this picker takes the approach of changing the type date always to text to prevent double date pickers.


But how can you tell if the browser has support for the native picker? You can't.

That's what I was wondering. If there were a way, it'd be pretty awesome to use a library like this as a polyfill rather than as a separate thing you attach to text inputs.


You can. Modernizr will tell you if the browser supports the native picker. http://modernizr.com/


It doesn't tell that. From Modernizr wiki[0]: "webforms UI: datepicker, colorpicker UIs cannot be detected, only the associated constraint validation"

[0]: https://github.com/Modernizr/Modernizr/wiki/Undetectables


These libraries always make me sad by neglecting to include a time picker.


this is a cool and easy addon to jq.ui datepicker https://github.com/trentrichardson/jQuery-Timepicker-Addon


Looks great. I like that it is big with plenty of spacing. Most date pickers seem to squish together the numbers without any apparent reason.

It'd be so helpful if makers of these js elements put screenshots of what the element looks like on top 3 mobile devices. Of course, this raises the question that they would need access to these devices. Which raises the question, for people who do mobile-heavy web dev, how do you test things rapidly beside having an iPhone next to you to constantly hit refresh?


iOS Simulator with desktop Safari's inspector if needed. If it is a more simple page then a separate browser window resized to mobile size.


Thanks! Also just found browserstack.com


Looks like a really nice jQuery alternative from yui3 calendar (http://yuilibrary.com/yui/docs/calendar/ )


This doesn't seem to work on IE9 (either that, or I just don't understand how it's supposed to work). All of the examples appear to me as plain old editable text fields.


I really like the datepicker on https://www.google.com/flights/. I wish someone would clone it for jQuery.


It seems to be far faster than the rest of the datepickers people have linked to on this page, as well. Feels great to use.


"Bind it like this: $( '.datepicker' ).datepicker()" - so the very first instruction is an incorrect reference to JavaScript 'binding' as something that extends or provides features to an element, vs what it truly does: change the scope reference of the 'this' keyword in a function. Oh jQuery, thank you for obscuring the actual JavaScript language for developers everywhere sigh


Looks great! And with a few (minor) modifications I was able to get it to work with a non-jQuery framework! Thanks for that. I'm getting fed up with all of these ".js" projects that rely heavily on jQuery when they don't need to. I'm going to keep this library in mind for a project I'm working on.


Nice work, thanks for the contribution. Will definitely use. Funny thing to, just created a web app that centers around a calendar and date picking. Was using jQuery UI datepicker but with some tweaking, I might use this.


> whereas jQuery UI datepicker is 42kb minified

For anyone who cares, the Closure Compiler gets jQuery UI Datepicker down to 30kb (11kb gzipped).

Not quite as drastic as he claims but still significantly larger compared to his 6.7kb (2.8kb gzipped).


What functionality is sacrificed for size?


Some more missing stuff: does not allow to block specific days or weekdays (e.g. sundays) that should not be picked. Also time ranges (hover over a days and the next x days get highlighted) would be nice.


Just submitted an "issue" about that: https://github.com/amsul/pickadate.js/issues/6



Looks cool but on iOs it won't let you close the picker unless you select a date other than what's selected. Touching the input again might be a good way to close it.


When pairing this up with jqueryui js on the same page, none of it seems to be working. Not sure why, seems to not have the proper name spacing?


So i guess im answering my own question here. jqueryui names their datepicker under the same function name, I have to have jqueryUI and dont have the capacity to install a custom version of jquery ui to remove datepicker so this is basically useless to me.


Can it default to the native date selector on mobile?


I'd like a second click in the date field to dismiss the date picker. That doesn't happen in the demo at least.


Would be great if you make an option to be able to pick two dates (intervals) just like in Google Analytics.


I do so wish this came out about a week ago. I had to resort to jQuery UI's datepicker for a thing at work.


Very nice library! One question though: how easy would it be to make the datepicker responsive?


+1 on years - for selecting your birthdate, it'd take quite a while. Besides that, nice job!


Arrows should be added around the year for quicker traversal through years.


pickadate is just as opinionated as jquery ui. why must component writers insist on hard-coded (and non-customisable) use-cases. there's simply no need to mandate an `input` element.


You might enjoy my attempt. No jQuery dependency and binding to an input field is optional.

https://github.com/dbushell/Pikaday


Some missing features: - Week starting on mondays - Week numbers


The messages and dates they use on the demo page are fantastic.


Why am I not able to pick today's date? (November 20, 2012)


new builds of this have resolved all these issues: http://amsul.github.com/pickadate.js/


How does this differ from the jquery UI datepicker?


Weighs 6.66kb (2.8kb gzipped) whereas jQuery UI datepicker is 42kb minified (or 30kb (11kb gzipped) via the Closure Compiler).


How much of that code on UI is for accessibility or backwards compatibility


How is this better than the Bootstrap datepicker?


For non-phones, what about a 4x3 grid of months?


You should add it to http://microjs.com/


I thought the idea behind microjs was libraries/frameworks that didn't require monoliths (like jQuery).


Doi, didn't read thought it was a stand alone date picker.


Wish it allowed me to type in the box..the interaction is a bit confusing..


This was actually the first thing I tried, half expecting it to smart match the text.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: