Repository: streamlit/streamlit

Issue:
date_input cannot go before January, 2000 
# Summary

`st.date_input` widget is unable to go before January 2000, e.g. 1999,1990, etc… It doesn’t matter if you use the dropdown box or the left arrow, because when it arrives in January 2000 the left arrow disappears.

# Steps to reproduce
1. Put a `st.date_input` in your app
2. Try using arrows/or scroll in the dropdown menu before date: January 2000

You can actually set a date before January 2000 if you initialize it using `value` parameter, e.g.
` d = st.date_input('When's your birthday', datetime.date(1980, 7, 6))`
But even in this case, you don't see the left arrow anymore only the right one, also the dropdown still only shows Januar 2000.

## Expected behavior:

Use the arrows or scroll through the dropdown box to go at any date in the past (or at least till 1900).

## Actual behavior:

As soon as you reach at January, 2000 the left arrow disappears and also the scroll ends.

## Is this a regression?

I don't know, because I haven't used it in the past.

# Debug info

- Streamlit version: 0.50.2
- Python version: 3.7.3
- Using venv
- OS version: ManjaroLinux 18.1.2
- Browser version: Mozilla Firefox 70.0 (64-bit)/Google Chrome 72.0.3626.121 (Official Build) (64-bit)

# Additional information
![Screenshot_2019-11-24 tax_calculator · Streamlit(1)](https://user-images.githubusercontent.com/7949935/69529936-7bbe1f80-0f71-11ea-877e-fd5c1af5a587.png)
![Screenshot_2019-11-24 tax_calculator · Streamlit](https://user-images.githubusercontent.com/7949935/69529937-7bbe1f80-0f71-11ea-84de-8134ec307750.png)
![Screenshot_2019-11-25 tax_calculator · Streamlit](https://user-images.githubusercontent.com/7949935/69530045-ab6d2780-0f71-11ea-9d3c-7c0014f9009e.png)

Original discussion: [https://discuss.streamlit.io/t/date-input-cannot-set-before-january-2000/1126](https://discuss.streamlit.io/t/date-input-cannot-set-before-january-2000/1126)



Discussion:
Baseweb's Datepicker is all kinds of broken. I've filed a bug against it here: https://github.com/uber/baseweb/issues/2418

We should reprioritize based on their response?
@kantuni created a patch in Baseweb for this, here: https://github.com/uber/baseweb/issues/2418

We need to update to the latest Baseweb (and help make sure the patch gets merged). I'll put this ticket on hold until then.
Hi, this seems to be still broken in streamlit 0.55.0.
Any chance to get it fixed ? Thanks !
Looks like the patch has been merged and we're on the latest Baseweb. 

The issue is fixed on the Baseweb site, but it requires passing in a `minDate` argument to the component that's lower than `2000/01/01` which looks to be the default.

We need to handle `minDate` in Streamlit or lower the default value to something reasonable.

Resolving patch:
diff --git a/e2e/scripts/st_date_input.py b/e2e/scripts/st_date_input.py
--- a/e2e/scripts/st_date_input.py
+++ b/e2e/scripts/st_date_input.py
@@ -16,7 +16,7 @@
 from datetime import datetime
 from datetime import date
 
-w1 = st.date_input("Label 1", date(1970, 1, 1))
+w1 = st.date_input("Label 1", date(1970, 1, 1), min_value=date(1970, 1, 1))
 st.write("Value 1:", w1)
 
 w2 = st.date_input("Label 2", datetime(2019, 7, 6, 21, 15))
diff --git a/lib/streamlit/DeltaGenerator.py b/lib/streamlit/DeltaGenerator.py
--- a/lib/streamlit/DeltaGenerator.py
+++ b/lib/streamlit/DeltaGenerator.py
@@ -2351,16 +2351,20 @@ def time_input(self, element, label, value=None, key=None):
         return current_value
 
     @_with_element
-    def date_input(self, element, label, value=None, key=None):
+    def date_input(self, element, label, value=None, min_value=datetime.min, max_value=None, key=None):
         """Display a date input widget.
 
         Parameters
         ----------
         label : str
             A short label explaining to the user what this date input is for.
-        value : datetime.date/datetime.datetime
+        value : datetime.date or datetime.datetime
             The value of this widget when it first renders. This will be
             cast to str internally. Defaults to today.
+        min_value : datetime.date or datetime.datetime
+            The minimum selectable date. Defaults to datetime.min.
+        max_value : datetime.date or datetime.datetime
+            The maximum selectable date. Defaults to today+10y.
         key : str
             An optional string to use as the unique key for the widget.
             If this is omitted, a key will be generated for the widget
@@ -2397,6 +2401,20 @@ def date_input(self, element, label, value=None, key=None):
         element.date_input.label = label
         element.date_input.default = date.strftime(value, "%Y/%m/%d")
 
+        if isinstance(min_value, datetime):
+            min_value = min_value.date()
+
+        element.date_input.min = date.strftime(min_value, "%Y/%m/%d")
+
+        if max_value is None:
+            today = date.today()
+            max_value = date(today.year+10, today.month, today.day)
+
+        if isinstance(max_value, datetime):
+            max_value = max_value.date()
+
+        element.date_input.max = date.strftime(max_value, "%Y/%m/%d")
+
         ui_value = _get_widget_ui_value("date_input", element, user_key=key)
         current_value = (
             datetime.strptime(ui_value, "%Y/%m/%d").date()


Test patch:
diff --git a/frontend/src/components/widgets/DateInput/DateInput.test.tsx b/frontend/src/components/widgets/DateInput/DateInput.test.tsx
--- a/frontend/src/components/widgets/DateInput/DateInput.test.tsx
+++ b/frontend/src/components/widgets/DateInput/DateInput.test.tsx
@@ -19,6 +19,7 @@ import React from "react"
 import { shallow } from "enzyme"
 import { fromJS } from "immutable"
 import { WidgetStateManager } from "lib/WidgetStateManager"
+import { DateInput as DateInputProto } from "autogen/proto"
 
 import DateInput, { Props } from "./DateInput"
 import { Datepicker as UIDatePicker } from "baseui/datepicker"
@@ -27,11 +28,12 @@ jest.mock("lib/WidgetStateManager")
 
 const sendBackMsg = jest.fn()
 
-const getProps = (elementProps: object = {}): Props => ({
+const getProps = (elementProps: Partial<DateInputProto> = {}): Props => ({
   element: fromJS({
     id: 1,
     label: "Label",
     default: "1970/01/01",
+    min: "1970/1/1",
     ...elementProps,
   }),
   width: 0,
@@ -102,4 +104,22 @@ describe("DateInput widget", () => {
       { fromUi: true }
     )
   })
+
+  it("should have a minDate", () => {
+    expect(wrapper.find(UIDatePicker).prop("minDate")).toStrictEqual(
+      new Date("1970/1/1")
+    )
+    expect(wrapper.find(UIDatePicker).prop("maxDate")).toBeUndefined()
+  })
+
+  it("should have a maxDate if it is passed", () => {
+    const props = getProps({
+      max: "2030/02/06",
+    })
+    const wrapper = shallow(<DateInput {...props} />)
+
+    expect(wrapper.find(UIDatePicker).prop("maxDate")).toStrictEqual(
+      new Date("2030/02/06")
+    )
+  })
 })