Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 22 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
This is a React Native Date Picker with following main features:

📱&nbsp; Supports iOS, Android and Expo<br>
🕑&nbsp; 3 different modes: Time, Date, DateTime<br>
🕑&nbsp; 4 different modes: Time, Date, DateTime, YearAndMonth<br>
🌍&nbsp; Various languages<br>
🎨&nbsp; Customizable<br>
🖼&nbsp; Modal or Inlined<br>
Expand Down Expand Up @@ -181,7 +181,7 @@ export default () => {
| `maximumDate` | Maximum selectable date. <br/> Example: `new Date("2021-12-31")` |
| `minimumDate` | Minimum selectable date. <br/> Example: `new Date("2021-01-01")` |
| `minuteInterval` | The interval at which minutes can be selected. | <img src="docs/minute-interval-ios.png" alt="Date picker minute interval IOS" height="120px" /> | <img src="docs/minute-interval-android.png" alt="Date picker minute interval Android" height="120px" /> |
| `mode` | The date picker mode. `"datetime"`, `"date"`, `"time"` | <img src="docs/datetime-mode-ios.png" alt="React native date time picker" height="120px" /><img src="docs/date-mode-ios.png" alt="React native datepicker" height="120px" /><img src="docs/time-mode-ios.png" alt="React native time picker" height="120px" /> | <img src="docs/datetime-mode-android.png" alt="react native date time picker android" height="120px" /><img src="docs/date-mode-android.png" alt="react native datepicker android" height="120px" /><img src="docs/time-mode-android.png" alt="react native time picker android" height="120px" /> |
| `mode` | The date picker mode. `"datetime"`, `"date"`, `"time"`, `"yearAndMonth"` | <img src="docs/datetime-mode-ios.png" alt="React native date time picker" height="120px" /><img src="docs/date-mode-ios.png" alt="React native datepicker" height="120px" /><img src="docs/time-mode-ios.png" alt="React native time picker" height="120px" /> | <img src="docs/datetime-mode-android.png" alt="react native date time picker android" height="120px" /><img src="docs/date-mode-android.png" alt="react native datepicker android" height="120px" /><img src="docs/time-mode-android.png" alt="react native time picker android" height="120px" /> |
| `locale` | The locale for the date picker. Changes language, date order and am/pm preferences. Value needs to be a <a title="react native datepicker locale id" href="https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPInternational/LanguageandLocaleIDs/LanguageandLocaleIDs.html">Locale ID.</a> | <img src="docs/locale-ios.png" alt="React Native Date picker locale language ios" height="120px" /> | <img src="docs/locale-android.png" alt="React Native Date picker locale language android" height="120px" /> |
| `timeZoneOffsetInMinutes` | Timezone offset in minutes (default: device's timezone) |
| `is24hourSource` | Change how the 24h mode (am/pm) should be determined, by device settings or by locale. {'locale', 'device'} (android only, default: 'device') |
Expand Down Expand Up @@ -227,7 +227,7 @@ On iOS the 12/24h preference is determined by the `locale` prop. Set for instanc

### Is it possible to show only month and year?

This is unfortunately not possible due to the limitation in DatePickerIOS. You should be able to create your own month-year picker with for instance https://github.com/TronNatthakorn/react-native-wheel-pick.
Yes! You can use the `"yearAndMonth"` mode which displays only month and year selection on both platforms.

### Why does the Android app crash in production?

Expand All @@ -253,9 +253,9 @@ const [state, setState] = useState("idle")
<ConfirmButton disabled={state === "spinning"} />
```

## Three different modes
## Different picker modes

Here are some more info about the three different picker modes that are available.
Here are some more info about the different picker modes that are available.

### Date time picker

Expand Down Expand Up @@ -320,6 +320,23 @@ Set mode property to `time` to show the time picker:
/>
```

### Month Year picker

The yearAndMonth mode allows you to select only month and year, which is useful for selecting birth months, credit card expiration dates, or other month/year selections. This mode uses the native `UIDatePickerModeYearAndMonth`.

Set mode property to `yearAndMonth` to show the month year picker:

```jsx
<DatePicker
...
mode="yearAndMonth"
/>
```

**Compatibility Notes:**
- **iOS**: Displays the native year and month picker (`UIDatePickerModeYearAndMonth`)
- **Android**: Displays year and month wheels (without the date wheel)

## About

React Native Date Picker is a cross platform component for iOS and Android. It uses native code from respective platform to get the genuine look and feel the users expect. A strong motivation for creating this picker was the datetime mode on Android. It's quite unique for the platform and avoids two different picker popups, which normally is necessary. Instead, this datetime mode requires fewer user actions and enables a great user-experience.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ public ArrayList<WheelType> getVisibleWheels() {
visibleWheels.add(WheelType.DATE);
break;
}
case yearAndMonth: {
visibleWheels.add(WheelType.YEAR);
visibleWheels.add(WheelType.MONTH);
break;
}
}
if((mode == Mode.time || mode == Mode.datetime) && state.derived.usesAmPm()){
visibleWheels.add(WheelType.AM_PM);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package com.henninghall.date_picker.models;

public enum Mode {
date, time, datetime
date, time, datetime, yearAndMonth
}
18 changes: 18 additions & 0 deletions android/src/main/java/com/henninghall/date_picker/ui/Wheels.java
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,24 @@ private String getDateModeString(int daysToSubtract) {
return sb.toString();
}

private String getYearAndMonthString(int daysToSubtract) {
ArrayList<Wheel> wheels = getOrderedVisibleWheels();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 2; i++) {
if (i != 0) sb.append(" ");
Wheel w = wheels.get(i);
sb.append(w.getValue());
}
return sb.toString();
}

private String getDateString(int daysToSubtract){
if(state.getMode() == Mode.date ){
return getDateModeString(daysToSubtract);
}
if(state.getMode() == Mode.yearAndMonth ){
return getYearAndMonthString(daysToSubtract);
}
return dayWheel.getValue();
}

Expand Down Expand Up @@ -170,6 +184,10 @@ private String getDateFormatPattern(){
+ wheels.get(1).getFormatPattern() + " "
+ wheels.get(2).getFormatPattern();
}
if(state.getMode() == Mode.yearAndMonth){
return wheels.get(0).getFormatPattern() + " "
+ wheels.get(1).getFormatPattern();
}
return dayWheel.getFormatPattern();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public String toDisplayValue(String value) {

@Override
public boolean visible() {
return state.getMode() != Mode.date;
return state.getMode() != Mode.date && state.getMode() != Mode.yearAndMonth;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public ArrayList<String> getValues() {

@Override
public boolean visible() {
return state.getMode() != Mode.date;
return state.getMode() != Mode.date && state.getMode() != Mode.yearAndMonth;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public ArrayList<String> getValues() {

@Override
public boolean visible() {
return state.getMode() == Mode.date;
return state.getMode() == Mode.date || state.getMode() == Mode.yearAndMonth;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ private int getStartYear() {

@Override
public boolean visible() {
return state.getMode() == Mode.date;
return state.getMode() == Mode.date || state.getMode() == Mode.yearAndMonth;
}

@Override
Expand Down
2 changes: 1 addition & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export interface DatePickerProps extends ViewProps {
/**
* The date picker mode.
*/
mode?: 'date' | 'time' | 'datetime'
mode?: 'date' | 'time' | 'datetime' | 'yearAndMonth'

/**
* Date change handler.
Expand Down
7 changes: 7 additions & 0 deletions ios/RNDatePicker.mm
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,13 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &
if(newViewProps.mode == RNDatePickerMode::Time) [_picker setDatePickerMode:UIDatePickerModeTime];
if(newViewProps.mode == RNDatePickerMode::Date) [_picker setDatePickerMode:UIDatePickerModeDate];
if(newViewProps.mode == RNDatePickerMode::Datetime) [_picker setDatePickerMode:UIDatePickerModeDateAndTime];
if(newViewProps.mode == RNDatePickerMode::YearAndMonth) {
if (@available(iOS 17.4, *)) {
[_picker setDatePickerMode:UIDatePickerModeYearAndMonth];
} else {
[_picker setDatePickerMode:(UIDatePickerMode)4269]; // magic number from iOS team
}
}
// We need to set minuteInterval after setting datePickerMode, otherwise minuteInterval is invalid in time mode.
_picker.minuteInterval = _reactMinuteInterval;
}
Expand Down
29 changes: 23 additions & 6 deletions ios/RNDatePickerManager.mm
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,29 @@

@implementation RCTConvert(UIDatePicker)

RCT_ENUM_CONVERTER(UIDatePickerMode, (@{
@"time": @(UIDatePickerModeTime),
@"date": @(UIDatePickerModeDate),
@"datetime": @(UIDatePickerModeDateAndTime),
@"countdown": @(UIDatePickerModeCountDownTimer), // not supported yet
}), UIDatePickerModeTime, integerValue)
+ (UIDatePickerMode)UIDatePickerMode:(id)json
{
static NSDictionary *modes;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
modes = @{
@"time": @(UIDatePickerModeTime),
@"date": @(UIDatePickerModeDate),
@"datetime": @(UIDatePickerModeDateAndTime),
@"countdown": @(UIDatePickerModeCountDownTimer), // not supported yet
};
});

if ([json isEqualToString:@"yearAndMonth"]) {
if (@available(iOS 17.4, *)) {
return (UIDatePickerModeYearAndMonth);
} else {
return (UIDatePickerMode)4269;
}
}

return (UIDatePickerMode)[RCTConvertEnumValue("UIDatePickerMode", modes, @(UIDatePickerModeTime), json) integerValue];
}

@end

Expand Down
2 changes: 1 addition & 1 deletion npmREADME.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# React Native Date Picker

A cross platform <a href="https://github.com/henninghall/react-native-date-picker" title="React Native Date Pickers">react native date picker</a> component for android and ios. It includes 3 different modes: date, time, and datetime. The date picker is customizable and has multiple language support.
A cross platform <a href="https://github.com/henninghall/react-native-date-picker" title="React Native Date Pickers">react native date picker</a> component for android and ios. It includes 4 different modes: date, time, datetime, and yearAndMonth. The date picker is customizable and has multiple language support.

## Modal

Expand Down
3 changes: 0 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,6 @@
"ios": {
"componentProvider": {
"RNDatePicker": "RNDatePicker"
},
"modulesProvider": {
"RNDatePicker": "RNDatePickerManager"
}
}
}
Expand Down
8 changes: 6 additions & 2 deletions src/DatePickerIOS.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,12 @@
style: [styles.datePickerIOS, props.style],
date: props.date ? props.date.toISOString() : undefined,
locale: props.locale ? props.locale : undefined,
maximumDate: props.maximumDate ? props.maximumDate.toISOString() : undefined,
minimumDate: props.minimumDate ? props.minimumDate.toISOString() : undefined,
maximumDate: props.maximumDate

Check failure on line 26 in src/DatePickerIOS.js

View workflow job for this annotation

GitHub Actions / Check / Lint

Replace `·?·props.maximumDate.toISOString()` with `⏎······?·props.maximumDate.toISOString()⏎·····`
? props.maximumDate.toISOString()

Check failure on line 27 in src/DatePickerIOS.js

View workflow job for this annotation

GitHub Actions / Check / Lint

Replace `·?·props.minimumDate.toISOString()` with `⏎······?·props.minimumDate.toISOString()⏎·····`
: undefined,
minimumDate: props.minimumDate
? props.minimumDate.toISOString()
: undefined,
theme: props.theme ? props.theme : 'auto',
}

Expand Down
4 changes: 3 additions & 1 deletion src/propChecker.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ const heightCheck = new PropCheck(

const modeCheck = new PropCheck(
(props) =>
props && props.mode && !['datetime', 'date', 'time'].includes(props.mode),
props &&
props.mode &&
!['datetime', 'date', 'time', 'yearAndMonth'].includes(props.mode),
"Invalid mode. Valid modes: 'datetime', 'date', 'time'"
)

Expand Down
Loading