Does Mathematica have an interactive date input control that lets the user choose a date by browsing to a calendar view and returning the selected date as a date list? For example, something like the Datepicker in jQuery.
-
1$\begingroup$ No, it doesn't. But it shouldn't be difficult to build one using the basic controls that are available. $\endgroup$– Sjoerd C. de VriesCommented Dec 18, 2012 at 15:35
-
$\begingroup$ Maybe a starting point here. $\endgroup$– b.gates.you.know.whatCommented Dec 18, 2012 at 16:05
-
$\begingroup$ There is also some Wolfram examples with date pickers but looks like @rm -rf has delivered :) $\endgroup$– Mike HoneychurchCommented Dec 18, 2012 at 20:52
-
4$\begingroup$ I don't know if it is smart about about picking dates, but there is this for finding stable marriages. (Or did you mean to pick dates from trees? That part was ambiguous...) $\endgroup$– Daniel LichtblauCommented Jan 2, 2013 at 16:39
4 Answers
Date-picker implementation in Mathematica
The following is my implementation of a simple date-picker. The current date is highlighted in LightBlue
and the weekends are highlighted in LightGreen
. The selected date is always highlighted in LightRed
(the default selection is the current date).
You can tap into this calendar by using the Dynamic
values for year
, month
and date
for your custom function (a simple example in the last Panel
).
Code:
Note that the following implementation uses DayName
, which was introduced in version 9. You might have to roll your own if you want to use this in earlier versions of Mathematica.
With[{startDayOffset = Thread[{Sunday, Monday, Tuesday, Wednesday, Thursday,
Friday, Saturday} -> Range@7]},
DynamicModule[{month, year, date, today = DateList[][[;;3]], daysInMonth, calendarView},
{year, month, date} = today;
daysInMonth[m_Integer,y_Integer] := DatePlus[{y, m, 1}, {{1, "Month"}, {-1, "Day"}}][[3]];
calendarView[m_Integer, y_Integer] := Grid[
{Style[#, FontWeight -> Bold]& /@ {"Su","M","Tu","W","Th","F","Sa"}} ~Join~
Partition[Range@daysInMonth[m, y], 7, 7, {DayName[{y, m, 1}] /. startDayOffset, 1}, {""}],
Frame -> All,
FrameStyle -> LightGray
] /. { i_Integer :> Button[
i,
date=i,
Appearance->"Palette",
Background -> Which[
date==i, LightRed,
{year, month, i} === today, LightBlue,
!FreeQ[DayName[{year, month, i}],Saturday|Sunday],LightGreen,
True,White
],
ImageSize->{32,32}
],
s_String :> Button[
s,
,
Appearance -> "Palette",
Enabled -> False,
Background -> If[!s == "", LightGray],
ImageSize->{32,32}
]
};
Panel[
Column[{
Row[{
Style["Year ",FontSize->16], PopupMenu[Dynamic@year, 1970 ~Range~ 2020],Spacer[10]
Style["Month ",FontSize->16],PopupMenu[Dynamic@month, Range@12 ]
}],
Dynamic@calendarView[month, year],
Panel[Dynamic@StringForm["Selected date: `1`/`2`/`3`", date, month, year]]
}]
]
]
]
-
7$\begingroup$ +1 That's a really nice bit of Mathematica code. And, unlike the Mayan calendar, it doesn't stop in a couple of days. $\endgroup$ Commented Dec 19, 2012 at 9:16
-
2$\begingroup$ No month rules, leap year stuff and data necessary if you just use
DatePlus[date, {{1, "Month"}, {-1, "Day"}}][[3]]
, withdate
the first of the month you're interested in. $\endgroup$ Commented Dec 20, 2012 at 22:50 -
$\begingroup$ @SjoerdC.deVries Thanks, that's much better :) Updated $\endgroup$– rm -rf ♦Commented Dec 21, 2012 at 4:05
There is a built-in DateSetter
:
{Developer`DateSetter[Dynamic@date], Dynamic@date}
By default the first selectable date is tomorrow and one can only go to future months. However, the option NotebookTools`DateSetterRange
can be used to set the first selectable date to sometime in the past,
{Developer`DateSetter[Dynamic@date, NotebookTools`DateSetterRange -> {2015, 1, 1}],
Dynamic@date}
or to only allow a certain date range.
{Developer`DateSetter[Dynamic@date,
NotebookTools`DateSetterRange -> {{2015, 1, 1}, {2015, 5, 2}}],
Dynamic@date}
-
$\begingroup$ +1. Do you know which versions have this function? $\endgroup$ Commented Nov 7, 2015 at 21:58
-
$\begingroup$ @MichaelE2 No, I don't know. I'm only aware that version 9.0.1 already has it, but without proper functioning. $\endgroup$– Karsten7Commented Nov 7, 2015 at 23:09
-
$\begingroup$ Note this comment by JxB. Apparently their answer was inspired by this but it supposedly crashes the frontend. $\endgroup$– rm -rf ♦Commented Nov 8, 2015 at 17:28
-
1$\begingroup$ This has no way to visit past months, but for me it's reliable so long as I only need the present or future. $\endgroup$ Commented May 27, 2016 at 17:16
-
$\begingroup$ @MichaelStern By default the first selectable date is tomorrow and one can only go to future months. However, there is the option
NotebookTools`DateSetterRange
. I'll add two examples how it can be applied to my answer. $\endgroup$– Karsten7Commented May 27, 2016 at 17:48
Here is one that should work in version 6 and later. The full code is at bottom.
Here is what it looks like:
{dateSetter[Dynamic[d]],Dynamic[d]}
I did not incorporate the year here, but you could put it in a Tooltip or add it to the button's graphic.
And when you click on the button you get
Incorporate this into a Manipulate
using {d,dateSetter[#]&}
as a control:
Manipulate[DynamicModule[{difference},
difference=DateDifference[DateList[][[1;;3]],d];Style[Row[{DateString[d,{"DayShort"," ","MonthName"," ","Year"}]," ",difference/.{x_/;x<-1:>Row[{"was ",-x," days ago."}],
x_/;x==-1->"was yesterday.",
x_/;x==0->"is today.",
x_/;x==1->"is tomorrow.",
x_:>Row[{"is ",x," days from now."}]}}],"Text"]],{{d,DateList[][[1;;3]],""},dateSetter[#]&}]
The code:
Clear[monthDays];
monthDays[year_,month_]:=DateDifference[DateList@{year,month},DateList@{year,month+1}];
monthDays[date_List/;Length@date<=6]:=monthDays[date[[1]],date[[2]]];
monthDays[date_String]:=monthDays@@DateList[date][[1;;2]];
Clear[monthDates];
monthDates[year_,month_]:=DatePlus[DateList@{year,month,0},#]&/@Range[monthDays[year,month]];
monthDates[date_List/;Length@date<=6]:=monthDates[date[[1]],date[[2]]];
monthDates[date_String]:=monthDates@@DateList[date][[1;;2]];
Clear[dayNames];
dayNames[]=DateString[{0,0,#},"DayNameShort"]&/@Range[-1,5];
Clear[dayOfWeek];
dayOfWeek[date_List]:=DateString[date,{"DayNameShort"}]/.Thread[dayNames[]->Range[0,6]];
dayOfWeek[year_,month_]:=dayOfWeek[{year,month,1}];
Clear[previousMonth];
previousMonth[year_,month_]:=Take[monthDates[year,month][[All,3]],-dayOfWeek[year,month]];
Clear[nextMonth];
nextMonth[year_,month_]:=Take[monthDates[year,month+1][[All,3]],7-dayOfWeek[year,month+1]];
Clear[monthArray];
monthArray[year_,month_]:=Module[{array},array=Partition[Join[Button[Style[#,Gray,Bold,FontFamily->"Helvetica"],Appearance->None,ImageSize->All,Enabled->False]&/@previousMonth[year,month],Button[Style[#,Darker[Cyan,.4],Bold,FontFamily->"Helvetica"],DialogReturn[{year,month,#}],Appearance->None,ImageSize->All]&/@monthDates[year,month][[All,3]],Button[Style[#,Gray,Bold,FontFamily->"Helvetica"],Appearance->None,ImageSize->All,Enabled->False]&/@nextMonth[year,month]],7,7,1,{}];
If[Length@array<6,Append[array,ConstantArray[Button[Style["",Gray,Bold,FontFamily->"Helvetica"],Appearance->None,ImageSize->All,Enabled->False],7]],array]]
Clear[dateSetter];
dateSetter[Dynamic[date_]]:=DynamicModule[{tmpdate,mousepos,storeddate},
If[Length@date<3,date=storeddate=tmpdate=DateList[][[1;;3]],tmpdate=storeddate=date];
Button[Dynamic[Graphics[{Lighter[Red,.3],Rectangle[{0,.6},{1,1},RoundingRadius->.1],
White,Rectangle[{0,0},{1,.5},RoundingRadius->.1],
Rectangle[{0,.3},{1,0.7}],
EdgeForm[GrayLevel[0.4]],FaceForm[],Rectangle[{0,0},{1,1},RoundingRadius->.1],
White,Text[Style[DateString[storeddate,{"MonthNameShort"}],Bold,FontFamily->"Helvetica"],{0.5,0.85}],
GrayLevel[0.3],Text[Style[DateString[storeddate,{"DayShort"}],Bold,FontFamily->"Helvetica",FontSize->Scaled[.5]],{0.5,0.35}]},
ImageSize->40]],
mousepos=MousePosition["ScreenAbsolute"];
tmpdate=DialogInput[Dynamic@Style[Grid[Join[{{Row[{Button[Style["\[LeftPointer]\[LeftPointer]",Medium,Bold,FontFamily->"Helvetica"],tmpdate=DatePlus[tmpdate,{-1,"Year"}],ImageSize->All,Appearance->None],
Button[Style["\[LeftPointer]",Medium,Bold,FontFamily->"Helvetica"],tmpdate=DatePlus[tmpdate,{-1,"Month"}],ImageSize->All,Appearance->None]},Spacer[3]],
Style[DateString[tmpdate,{"MonthName"," ","Year"}],Bold,FontFamily->"Helvetica",Medium],
SpanFromLeft,SpanFromLeft,SpanFromLeft,SpanFromLeft,
Row[{Button[Style["\[RightPointer]",Medium,Bold,FontFamily->"Helvetica"],tmpdate=DatePlus[tmpdate,{1,"Month"}],ImageSize->All,Appearance->None],
Button[Style["\[RightPointer]\[RightPointer]",Medium,Bold,FontFamily->"Helvetica"],tmpdate=DatePlus[tmpdate,{1,"Year"}],ImageSize->All,Appearance->None]},Spacer[3]]}},
{Style[#,FontFamily->"Helvetica",Medium]&/@dayNames[]},
monthArray[tmpdate[[1]],tmpdate[[2]]]],Background->{{None},{GrayLevel[0.8]}},Frame->True,Spacings->{.5,.5}],Small,FontFamily->"Helvetica"],
WindowMargins->{{mousepos[[1]],Automatic},{Automatic,mousepos[[2]]}},WindowElements->None,WindowFloating->True];
If[tmpdate=!=$Failed,date=storeddate=tmpdate,tmpdate=date],Method->"Queued",
Appearance->None]
]
-
$\begingroup$ The appearance and functionality is inspired by
Developer`DateSetter[]
, pointed out to me by @WReach. That function is not documented, and it crashes my front end session quite reliably. $\endgroup$– JxBCommented Jan 2, 2013 at 9:33 -
$\begingroup$ I think that you forgot to include the
monthDates
definition. $\endgroup$ Commented Jan 2, 2013 at 17:56 -
$\begingroup$ @GustavoDelfino It's there right after the
Clear[monthDates]
. $\endgroup$– JxBCommented Jan 2, 2013 at 18:36 -
$\begingroup$ Thank you @JxB. I fell victim to the invisible scroll bars in Mac OS X. $\endgroup$ Commented Jan 4, 2013 at 16:20
Here's a silly one that works only in version 9:
DynamicModule[{x = 0}, AngularGauge[Dynamic[x], {0, 365},
GaugeFrameStyle -> Black,
GaugeFrameSize -> .01,
ScaleDivisions -> 0,
GaugeFaceStyle -> Directive[LightGreen, EdgeForm[]],
GaugeFaceElementFunction -> "PlateauSector",
GaugeLabels ->
Dynamic[
Style[
DateString[
DatePlus[{2013, 1, 1}, x], {"DayName", " ", "MonthName", " ",
"Day" , ", ", "Year"}], 10 , Bold, Gray]]]]